我有一个应用程序,其中对象可能位于多个列表中的一个列表中。一个列表的UI需要将每个项目标记为位于其中一个其他列表中。
我实施的内容的简化版本是:
function Item(id, panel) {
var that = this;
this.id = id;
this.viewModel = panel;
this.isSelected = ko.computed(function(){
return panel.isSelected(that);
});
}
function Panel() {
var that = this;
//my two lists
this.all = ko.observableArray();
this.selected = ko.observableArray();
this.isSelected = function(item){
return _(that.selected()).find(function(thing){
console.log("iterating");
return thing.id == item.id;
});
};
}
var panel = new Panel();
ko.applyBindings(panel);
//add some things to the list
for(var i=0; i<40; i++){
var item = new Item(i, panel)
panel.all.push(item);
//let's select some of them. note it's actually a different object
if (i % 2 == 0){
panel.selected.push(new Item(i, panel));
}
};
小提琴在这里:http://jsfiddle.net/89j52/5/
因此,除了给项目提供参考的奇怪之外,它也表现得非常糟糕。这是因为每次您向选定列表添加另一个项目时,它会重新计算所有项目的选定状态;注意它打印“迭代”的次数。我理解为什么会这样做,但这很痛苦。
现在显然,每次添加时, 都不需要检查每个项目。例如,我可以为项目存储查找表,然后在将某些内容添加到所选列表时更新正确的查找表。但我不确定如何将其与Knockout的可观察/计算内容相结合,并使UI更新无缝。我应该如何在Knockout的习语中解决这个问题?
答案 0 :(得分:1)
如果您将 isSelected 转换为常规可观察(未计算)并在每次将项目添加到所选列表时直接更新,该怎么办:
function select(item){
panel.selected.push(item);
var itemInAll = _(panel.all()).find(function(thing){
return thing.id === item.id;
});
itemInAll.isSelected(true);
}
不是很优雅,但绝对更有效率。您也不需要在 Item 中保留对 panel 的引用。以下是完整代码:http://jsfiddle.net/89j52/9/