简体   繁体   中英

Knockout and observable array mismatch

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?

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/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM