Knockout mapping> mapped arrays are always updated

Violinist is here: http://jsfiddle.net/u9PLF/

I have a list of parents with nested children. I periodically update the entire hierarchy of objects and update the first parent child array once. The problem I am facing is that it seems that the children array is always being updated, or at least notifying subscribers every time I call the fromJS function.

I expect that the observed children will only notify subscribers once (when it first changes from [A, B] to [A, B, C], and not to subsequent calls).

What am I doing wrong?

thank

the code:

var data = {
    parents: [{
        id: 1,
        name: 'Scot',
        children: ['A', 'B']
    }]
};

function ParentVM(data) {
    var self = this;

    ko.mapping.fromJS(data, {}, self);

    self.count = ko.observable(0);

    self.hello = ko.computed(function () {
        console.log("Update", self.children());
        self.count(self.count() + 1);
    });
}

var mapping = {
    parents: {
        create: function (options) {
            return new ParentVM(options.data);
        },
        key: function (data) {
            return ko.utils.unwrapObservable(data.id);
        }
    }
};

var viewModel = ko.mapping.fromJS(data, mapping);
ko.applyBindings(viewModel);

setInterval(function () {

    var data = {
        parents: [{
            id: 1,
            name: 'Scott',
            children: ['A', 'B', 'C']
        }]
    };

    ko.mapping.fromJS(data, mapping, viewModel);
}, 2000);

viewModel.parents.subscribe(function () {
    console.log("Parents notif");
});
+4
1

@ . ko.mapping, ko.observable .

http://jsfiddle.net/C7wUb/

items([1,2])

var vm = {
    items: ko.observable([1,2]),
    count: ko.observable(0)
};

vm.items.subscribe(function(new_v) {
    console.log("items are updated to " + new_v);
    vm.count(vm.count() + 1);
});

ko.applyBindings(vm);

setInterval(function() {
    vm.items([1,2]);
}, 2000);

ko Comparer , .

// src/subscribables/observable.js
ko.observable['fn'] = {
    "equalityComparer": valuesArePrimitiveAndEqual
};

// src/subscribables/extenders.js
var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };
function valuesArePrimitiveAndEqual(a, b) {
    var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
    return oldValueIsPrimitive ? (a === b) : false;
}

, .

http://jsfiddle.net/u9PLF/2/

var oldComparer = ko.observable.fn.equalityComparer;

ko.observable.fn.equalityComparer = function(a, b) {
    var i, toStr = Object.prototype.toString;
    if (toStr.call(a) === '[object Array]' && toStr.call(b) === '[object Array]') {
        if (a.length !== b.length) return false;
        for (i = 0; i < a.length; i++) {
            if (!oldComparer(a[i], b[i])) return false;
        }
        return true;
    } else {
        return oldComparer(a, b);
    }
};

( Comparer childrenrayray, ., ko.extenders notify src/subscription/extenders.js)

, , self.hello = ko.computed(...), .

self.hello = ko.computed(function () {
    console.log("Update", self.children()); // you want to notify self.hello when children change.
    self.count(self.count() + 1); // but self.hello also has dependency on self.count()
});

, subscribe, .

self.children.subscribe(function(new_v) {
    console.log("Update", new_v);
    self.count(self.count() + 1);
});
+3

Source: https://habr.com/ru/post/1537585/


All Articles