我的Appmodel包含一个可观察的评论数组
self.comments=ko.observableArray([]); // Default Value is an empty array
/*
Here comes some code to initially fill the observable array
with items from an JSON Response
*/
此外,我有两个计算器应该代表第一个注释和最后一个注释
self.firstComment = ko.computed(function () {
var sorted = self.comments.sort(function (left, right) {
return left.Id() - right.Id();
});
return sorted[0];
});
self.lastComment = ko.computed(function () {
var sorted = self.comments.sort(function (left, right) {
return left.Id() - right.Id();
});
return sorted[sorted.length - 1];
});
这非常适用于初始化应用程序(从服务器加载JSON,构建应用程序模型......),但是当我向数组添加注释时,计算结果无法识别数组项的数量已更改(据我所知,一个可观察的数组只是一个可观察数组属性本身的可观察数据。所以当我这样做时:
self.comments.push(aNewCommentObject);
self.lastComment仍然绑定到数组项,这是最初加载应用程序的时候。
我发现this blog post如何通过引入虚拟可观察来强制计算,但我不喜欢这种方法。为什么使用observableArray以及如何使用?
其他挑战:我想在每种情况下保持observableArray项目的排序(因为它的评论Feed应该按时间顺序排序)。我尝试用计算commentsSorted
来做这个,但也有问题,当observableArray有新项时这不会更新,所以这里也是同样的问题。这就是原因,为什么我每次都在firstComment和lastComment中进行排序。
答案 0 :(得分:4)
尝试解开注释以触发Knockout的依赖关系跟踪:
self.firstComment = ko.computed(function () {
var sorted = self.comments().sort(function (left, right) {
// -------------------^^ !
return left.Id() - right.Id();
});
return sorted[0];
});
或(同样的事):
self.firstComment = ko.computed(function () {
var sorted = ko.unwrap(self.comments).sort(function (left, right) {
return left.Id() - right.Id();
});
return sorted[0];
});
当然,您可以将其抽象为单独的计算结果。
self.commentsSorted = ko.computed(function () {
return self.comments().sort(function (left, right) {
return left.Id() - right.Id();
});
});
self.firstComment = ko.computed(function () {
return ko.unwrap(self.commentsSorted)[0];
});
由于计算器缓存了它们的返回值(就像其他所有可观察的一样),您不必担心多次调用self.commentsSorted
。只有当潜在的可观察数组出现机会时,它才会重新计算。
答案 1 :(得分:2)
你怎么能“在每种情况下保持observableArray项目的分类”?我的建议是不要尝试对原始数组进行排序(我将在下面更详细地描述陷阱),而是使用一个返回一个新的排序数组的计算observable:
self.commentsSorted = ko.computed(function () {
return self.comments.slice(0).sort(function (left, right) {
return left.Id() - right.Id();
});
});
了解JavaScript数组sort()
方法的一个重要事项是更改原始数组。 Knockout的observableArray
包含许多数组函数,因此可以直接在observableArray
对象上使用它们。这就是为什么你可以使用myObservableArray.sort()
而不是myObservableArray().sort()
。但这两者并不相同,因为Knockout以不同的方式包装数组mutator方法,大致如下:
sort: function (sortFunction) {
this.valueWillMutate();
var result = this.peek().sort(sortFunction);
this.valueHasMutated();
return result;
}
那么自动更改原始observableArray
?
很难理解发生了什么。很容易没有获得对数组的依赖,因此永远不会更新超过初始化,或者不通知更改,从而破坏其他元素获取正确的数组视图。
即使你确实正确设置了它,你现在已经创建了一个循环依赖,因为你有一些在数组更改时更新的东西,然后再次更新数组。虽然Knockout当前为计算的observable的同步更新禁用了这个(但是将来可能会改变),但如果使用手动订阅或使用throttle
选项计算,它将导致无限递归。
答案 2 :(得分:1)
替代解决方案,使用subscribe
:
self.comments = ko.observableArray([]);
self.comments.subscribe(function(comments) {
var sorted = comments.sort(function (left, right) {
return left.Id() - right.Id();
});
self.firstComment(sorted[0]);
self.lastComment(sorted[sorted.length - 1]);
});