Knockout and observable array mismatch

2019-04-14 10:49发布

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?

1条回答
狗以群分
2楼-- · 2019-04-14 11:04

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/

查看更多
登录 后发表回答