@Charlie is right. This is not related to ko.mapping, it's how ko.observable tests equality of values.
In this demo, items are updated every time when calling 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);
The deeper cause is the default implementation of ko's equalityComparer, it only compares primitive types.
// 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;
}
The way to avoid unnecessary update event on observableArray is to overwrite equalityComparer.
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);
}
};
(you can also overwrite equalityComparer only for children observableArray, see how ko.extenders notify
is implemented in src/subscribables/extenders.js)
BTW, the way you do self.hello = ko.computed(...)
is kind of risky.
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()
});
I think what you want is a simple subscribe
, register a callback for children change event.
self.children.subscribe(function(new_v) {
console.log("Update", new_v);
self.count(self.count() + 1);
});