敲除映射>映射的数组总是更新的
knockout mapping > mapped arrays always updated
此处的小提琴手:http://jsfiddle.net/u9PLF/
我收到了一份有嵌套孩子的父母的名单。我定期更新整个对象层次结构,并更新第一个父对象的子数组一次。我遇到的问题是,子数组似乎总是在更新,或者至少每次我调用fromJS函数时它都会通知订阅者。
我希望children observableArray只通知订阅者一次(当它第一次从[A,B]更改为[A,B,C]时,而不是在随后的调用中)。
我做错了什么?
感谢
代码:
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");
});
@查理是对的。这与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的equityComparer的默认实现,它只比较基元类型。
// 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;
}
避免observableArray上不必要的更新事件的方法是覆盖equityComparer。
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);
}
};
(您也可以只为子级observableArray覆盖equityComparer,看看ko.extenders notify
是如何在src/substrables/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
,为children更改事件注册一个回调。
self.children.subscribe(function(new_v) {
console.log("Update", new_v);
self.count(self.count() + 1);
});
相关文章:
- 如何在映射数组中添加换行符
- 无法通过数组映射绑定
- 映射数组ES6时考虑空值
- 映射数组数组
- 在node.js或JavaScript中映射数组的干净方法
- 在angularjs中从逗号分隔的字符串列表中分割和映射数组
- Javascript映射数组循环
- GSON数组到json,但已映射数组
- 映射数组到对象的深度基于单独的对象
- Jquery映射数组键和值
- 映射数组的对象到映射分组的对象键js不可变
- 映射数组(列表),并添加一个属性
- 如何使用async.js映射数组
- 有可能只映射数组的一部分吗?(Array.map())
- 击倒映射数组与不同类型的视图模型
- 如何将哈希映射数组插入Redis?(Node.js)
- 映射数组中的属性,并在JavaScriptes6中连接一个字符串
- Javascript映射数组最后一项
- 从web方法映射数组值
- Javascript映射数组'fromCharCode'(字符)