Reputation: 1579
I am having a weird issue with a page on my site. I am using ASP.NET MVC to send model data to the page.
I am showing a list of checkboxes based on objects in a Javascript array. When the page loads, it shows the items properly but does not select the ones in the selected items array.
Here's what the HTML looks like.
<!-- ko foreach: items -->
<p>
<input type="checkbox"
data-bind="checkedValue: $data, checked: $root.selectedItems" />
<span data-bind="text: Name"></span>
</p>
<!-- /ko -->
Here's what the Javascript looks like.
var Item = function (id, name) {
this.Id = id;
this.Name = name;
};
var model = {
items = ko.observableArray([]),
selectedItems = ko.observableArray([])
};
@foreach (var serverItem in serverItems) {
@:model.items.push(new Item('@serverItem.Id', '@serverItem.Name'));
}
@foreach (var selectedServerItem in selectedServerItems) {
@:model.selectedItems.push(new Item('@selectedServerItem.Id', '@selectedServerItem.Name'));
}
ko.applyBindings(model);
You would think that it would get selected because the objects are identical, but it doesn't. And when I do select the checkboxes, it adds additional items to the selectedItems
array instead of using the existing ones.
['1', 'Business To Business'], ['2', 'Business To Consumer'], ['1', 'Business To Business']
Can anyone explain to me why this is happening? Why is Knockout not understanding that checkboxes need to be checked based on objects and not primitives?
Solution I ended up with:
var items = [];
@foreach (var serverItem in serverItems) {
@:items[@serverItem.Id] = {Id: '@serverItem.Id', Name: '@serverItem.Name'};
@:model.items.push(items[@serverItem.Id]);
if (selectedServerItems.Any(si => si.Id == serverItems.Id)
@:model.selectedItems.push(items[@serverItem.Id]);
}
Now the checkboxes are properly selected when the page loads.
Upvotes: 1
Views: 1474
Reputation: 37540
The objects are identical, but they are different instances. Knockout does an ==
(or maybe ===
) to compare the items, and in JavaScript that will always return false for 2 different instances of an object, even if internally they are the same. This works fine for strings, however.
var foo1 = {foo: 1};
var foo2 = {foo: 1};
var foo3 = foo1;
console.log(foo1 == foo2); // false
console.log(foo1 == foo3); // true
You can see that in action in this fiddle... http://jsfiddle.net/Nk86C/1/
Upvotes: 3