所以是的,我可以订阅一个可观察的数组:
vm.myArray = ko.observableArray();
vm.myArray.subscribe(function(newVal){...});
问题是newVal
传递给函数的是整个数组。无论如何,我只能得到增量部分吗?说添加或删除的元素?
Answers:
从KnockoutJS 3.0开始,ko.observableArray上有一个arrayChange订阅选项。
var myArray = ko.observableArray(["Alpha", "Beta", "Gamma"]);
myArray.subscribe(function(changes) {
// For this example, we'll just print out the change info
console.log(changes);
}, null, "arrayChange");
myArray.push("newitem!");
在上面的回调中,changes参数将是如下所示的change对象的数组:
[
{
index: 3,
status: 'added',
value: 'newitem!'
}
]
对于您的特定问题,您希望收到有关新项目或已删除项目的通知。要使用Knockout 3来实现,它看起来像这样:
myArray.subscribe(function(changes) {
changes.forEach(function(change) {
if (change.status === 'added' || change.status === 'deleted') {
console.log("Added or removed! The added/removed element is:", change.value);
}
});
}, null, "arrayChange");
myArray.reverse(); // [{ index: 0, moved: 1, status: 'deleted', value: 'Alpha' },{ index: 1, moved: 0, status: 'added', value: 'Alpha' }]
也许应该检查没有move属性的已添加和已删除状态?
由于在其他地方找不到任何相关信息,因此我将添加一条答复,说明如何将其与TypeScript一起使用。
这里的关键是使用KnockoutArrayChange接口作为TEvent进行订阅。如果不这样做,它将尝试使用其他(非泛型)订阅,并会抱怨状态,索引和值不存在。
class ZoneDefinition {
Name: KnockoutObservable<String>;
}
class DefinitionContainer
{
ZoneDefinitions: KnockoutObservableArray<ZoneDefinition>;
constructor(zoneDefinitions?: ZoneDefinition[]){
this.ZoneDefinitions = ko.observableArray(zoneDefinitions);
// you'll get an error if you don't use the generic version of subscribe
// and you need to use the KnockoutArrayChange<T> interface as T
this.ZoneDefinitions.subscribe<KnockoutArrayChange<ZoneDefinition>[]>(function (changes) {
changes.forEach(function (change) {
if (change.status === 'added') {
// do something with the added value
// can use change.value to get the added item
// or change.index to get the index of where it was added
} else if (change.status === 'deleted') {
// do something with the deleted value
// can use change.value to get the deleted item
// or change.index to get the index of where it was before deletion
}
});
}, null, "arrayChange");
}
为了只检测push()
和remove()
事件,而不是移动项目,我把围绕这些观察到的阵列功能的包装。
var trackPush = function(array) {
var push = array.push;
return function() {
console.log(arguments[0]);
push.apply(this,arguments);
}
}
var list = ko.observableArray();
list.push = trackPush(list);
原始的push函数存储在一个闭包中,然后覆盖一个包装器,该包装器使我可以在将推入的项目推入数组之前或之后执行我想做的任何事情。
的相似模式remove()
。
我正在使用类似但不同的方法,请跟踪是否已在元素本身中检测到元素:
myArray.subscribe(function(array){
$.each(array, function(id, el) {
if (!el.instrumented) {
el.instrumented = true;
el.displayName = ko.computed(function(){
var fn = $.trim(el.firstName()), ln = $.trim(el.lastName());
if (fn || ln) {
return fn ? (fn + (ln ? " " + ln : "")) : ln;
} else {
return el.email();
}
})
}
});
})
但这确实很乏味,并且在我的代码中重复了这种模式
我不知道。想知道我在做什么?我使用以前的变量来保存值,这叫做selectedItem
vm.selectedItem = ko.observable({});
function addToArray(item) { vm.selectedItem(item); vm.myArray.push(item); }
这样,当我的可观察数组发生问题时,我知道添加了哪个项目。
vm.myArray.subscribe(function(newArray) { var addedItem = vm.selectedItem(item); ... }
这确实很冗长,并且假设您的数组包含多种数据,则需要具有某种标志,以帮助您了解如何处理保存的变量...
vm.myArray.subscribe(function(newArray) {
if ( wasUpdated )
// do something with selectedItem
else
// do whatever you whenever your array is updated
}
要通知一个重要的事情是,你可能知道哪些项目,如果你知道是否加入push
或unshift
使用。只需浏览数组的最后一项,或者浏览第一个,瞧。