Search code examples
javascriptjsonknockout.jsknockout-2.0knockout-3.0

Knockoutjs Dropdown Pre Selection In Nested Arbitary Javascript Object Working Fine KO 2x versions Not working in KO 3x versions


so this my sample data. which il be loading form server in json format construct into below looking objec graph. Its an array of "Choice" objects each will be having id, name, stages & currentStageId properties. "stages" property in "Choice" object is an array of "Stage" object which would be having id, name & value properties.The "Choice" object will go through no.of stages from "First Stage" to "Fourth Stage" so user can select a "Stage" from the give dropdown list and save it. "currentStageId" is the property which stores "id" of stage object which will give in which stage the respective "Choice" object is in

Note: each choice can have different types of stages for brevity kept simple as possible

i.e for Choice 1 the current saved stage is 4

var data = [
new Choice({
    id: 1,
    name: "One",
    stages: [
    new Stage({
        id: 1,
        name: "First Stage",
        value: 25
    }),
    new Stage({
        id: 2,
        name: "Second Stage",
        value: 50
    }),
    new Stage({
        id: 3,
        name: "Third Stage",
        value: 75
    }),
    new Stage({
        id: 4,
        name: "Fourth Stage",
        value: 100
    })],
    currentStageId: 4

}),
new Choice({
    id: 2,
    name: "Two",
    stages: [
    new Stage({
        id: 1,
        name: "First Stage",
        value: 25
    }),
    new Stage({
        id: 2,
        name: "Second Stage",
        value: 50
    }),
    new Stage({
        id: 3,
        name: "Third Stage",
        value: 75
    }),
    new Stage({
        id: 4,
        name: "Fourth Stage",
        value: 100
    })],
    currentStageId: 3

}),
new Choice({
    id: 3,
    name: "Three",
    stages: [
    new Stage({
        id: 1,
        name: "First Stage",
        value: 25
    }),
    new Stage({
        id: 2,
        name: "Second Stage",
        value: 50
    }),
    new Stage({
        id: 3,
        name: "Third Stage",
        value: 75
    }),
    new Stage({
        id: 4,
        name: "Fourth Stage",
        value: 100
    })],
    currentStageId: 2

})];

Here is "Choice" & "Stage" Modles to hold data and ViewModel for binding

function ViewModel(data) {
    var self = this;
    self.choices = ko.observableArray(data);
    //dont require pre selection so kept it with empty observable so it
    //will be set to first item in the dropdown list
    self.selectedChoice = ko.observable();
}

function Choice(data) {
   //debugger;
    this.id = data.id;
    this.name = data.name;
    //require pre selection of stage as choice can go through no of 
    //stages and selected stage name and value will be stored
    this.selectedStage = ko.observable(ko.utils.arrayFirst(data.stages, function (item) {
        return item.id === data.currentStageId;
    }));
    this.stages = ko.observableArray(data.stages);

}

function Stage(data) {
    this.id = data.id;
    this.name = data.name;
    this.value = data.value;
}
ko.applyBindings(new ViewModel(data));

Here is my view

<select data-bind="options: choices, optionsText: 'name', value: selectedChoice"></select>
<select data-bind="options: selectedChoice().stages, optionsText: 'name', value: selectedChoice().selectedStage"></select>

Knockout.js 2x version

  1. Pre selection of saved stage is working
  2. Selected stage for choice is updated into underlying observable

Here is the Working sample with KO 2x in js

Knockout.js 3x version

  1. Pre selection of saved stage is not working
  2. Selected stage for choice is not preserved. When choice is changed the selectedStage is set to first item in the dropdown list each and every time the choice is changed.

Here is the Working sample with KO 3x

Finally the actual part. Question!

  1. Why the same code behaving differently with two different versions of KO. Am i missing something new in KO? or is it a bug in KO?
  2. What code changes should be done to produce same fucntionality as in with later version of KO, using the latest version of KO? because my project is being developed with latest version konckout.js 3.1.0 and i don't wanna switch back to older version for this functionality.
  3. Which behavior of KO version is correct whether 2x or 3x? What is happening internally? which is causing this behavior discrepancies?

Thanks in advance.


Solution

  • I think it is related to 2. Bindings are now refreshed independently
    Now you should use selectedChoice move out from options binding, e.g.

    <div data-bind="with: selectedChoice">
       <select data-bind="options: stages, optionsText: 'name', value: selectedStage"></select>
    </div>