Reputation: 5761
Consider the following properties inside a viewmodel
self.allValues = ko.observableArray();
self.selectedValues = ko.observableArray();
On edit, selectedValues
contains values coming from database. Here is the problem: selectedValues
contains elements than are included on allValues
, but they are not the same instances. They are the same from properties values point of view but are actually different objects.
This causes that every time knockout uses indexOf
over allValues
using objects from selectedValues
always fails to find the object.
I'm using selectedValues
on a checked
binding but fails to check the correct elements included on this array.
<div class="vars-list" data-bind="foreach: allValues">
<input type="checkbox" data-bind="checkedValue: $data...(etc)
checked: selelectedValues" />
</div>
Is there any way for knockout to match objects by property values instead of memory address?
Upvotes: 2
Views: 251
Reputation: 16688
Using a custom binding is one way to go. Here's a variation of the checked
binding that uses a comparison function.
ko.bindingHandlers.checkedInArray = {
init: function (element, valueAccessor, allBindings) {
ko.utils.registerEventHandler(element, "click", function() {
var observable = valueAccessor(),
array = observable(),
checkedValue = allBindings.get('checkedValue'),
isChecked = element.checked,
comparer = allBindings.get('checkedComparer');
for (var i = 0, n = array.length;
i < n && !comparer(array[i], checkedValue);
++i) { }
if (!isChecked && i < n) {
observable.splice(i, 1);
} else if (isChecked && i == n) {
observable.push(checkedValue);
}
});
},
update: function (element, valueAccessor, allBindings) {
var array = valueAccessor()(),
checkedValue = allBindings.get('checkedValue'),
comparer = allBindings.get('checkedComparer');
for (var i = 0, n = array.length;
i < n && !comparer(array[i], checkedValue);
++i) { }
element.checked = (i < n);
}
};
jsFiddle: http://jsfiddle.net/mbest/4mET9/
Upvotes: 5