KnockoutJS options binding with duplicate values

2019-07-16 18:47发布

I'm building a simple app with Knockout.js as a proof of concept. As I'm very new to Knockout, the code in this question may be far from perfect and exhibit bad practices, so feel free to let me know if that's the case!

I'm using the options binding to produce the contents of a select element:

<select data-bind="options: titles, optionsText: 'display', optionsValue: 'value'">
</select>

The View Model looks like this:

var ViewModel = function() {
    this.titles = ko.observableArray([]);
};

On DOM ready I am pushing some values into that observable array (each value is an object literal, representing a "title", e.g. "Mr", "Mrs" etc):

var data = [
    { value: "Mr", display: "Default Value" },
    { value: "Miss", display: "Miss" },
    { value: "Mr", display: "Mr" },
    { value: "Ms", display: "Ms" }
];
ko.applyBindings(view);
for(var i = 0; i < data.length; i++) {
    view.titles.push(data[i]); //Push titles into observable array
}

Don't ask why there are two objects with the value "Mr", that's just the way the data I have to deal with comes. I can't change it. However, this is what causes the problem. I would expect the first object to represent the selected option, but that's not the case. The third object represents the option element that actually ends up as the default selection.

I believe this is due to the fact that the observable array causes the option elements to be added to the DOM one by one as the loop iterates. Knockout attempts to preserve the selected option by checking it's value. After the first iteration, the selected option has the value "Mr". After the third iteration there is another option with the value "Mr" so Knockout thinks that it was the previously selected option and selects it.

Here's a link to a fiddle demonstrating the problem. The "Default Value" option should be selected, but is not. If you click the button to add another option with the same value again, that becomes selected, but, according to the documentation, it should not.

My question is, how can this behaviour be prevented?

1条回答
放荡不羁爱自由
2楼-- · 2019-07-16 19:09

Why are you pushing items into array one by one? You could just do:

view.titles(data);

instead of

for(var i = 0; i < data.length; i++) {
    view.titles.push(data[i]); //Push titles into observable array
}

This would also fix your problem - the first item would be selected by default. Also, if you are not planning on adding new items to that array, you could use ko.observable instead of ko.observableArray

UPDATE: Knockoutjs doesn't seem to like multiple options with the same value. My code won't work properly if you add value binding to a select tag (it will select third item, not first). However, since knockoutjs allows you to access selected object (via value binding), you can remove optionsValue binding and access value via value binding: jsfiddle.net/ej9Ue/1

查看更多
登录 后发表回答