2012-07-02 34 views
37

我想知道如何创建一个可计算的可观察数组。如何在Knockout中创建一个可计算的可观察数组

在我的视图模型中,我有2个可观察数组,我想有一个计算可观数组,它只是两个数组的组合。

function ViewModel() { 
    var self = this; 
    self.listA= ko.observableArray([]); 
    self.listB = ko.observableArray([]); 
    self.masterList= //combine both list A and B 

回答

33

这将组合两个数组并返回组合列表。但是,它不是一个可计算的可观测数组(不知道这是否可能),而是一个经常计算的可观测数。

self.masterList = ko.computed(function() { 
    return this.listA().concat(this.listB()); 
}, this); 
+18

相信这个答案在大多数用例中都是有缺陷的:计算的observable的值是一个常规数组,而不是可观察数组(大致在答案中陈述)。因此,更新'listA'或'listB'将完全替换数组本身,而不是更新其内容(这是我们在99%的情况下所需的)。 **这意味着您不应该将视图绑定到此可观察对象。**实际上,此代码与非计算对象一样有用。查看不同方法的其他答案。 – tne

+0

在这种情况下它不起作用,但是淘汰赛插件[knockout-projections](https://github.com/stevesanderson/knockout-projections)使用新的[数组变更订阅]实现了效率更高的可观察数组http://blog.stevensanderson.com/2013/10/08/knockout-3-0-release-candidate-available/)。这个插件可以扩展以支持高效的concat操作。 – Singularity

7

observableArray只是一个具有更多属性的observable。因此,在闭包中返回一个数组的计算观察值将被视为一个数组。

+3

好吧,有点。我只是测试它,似乎除非它被声明为一个可观察数组,否则不会为你打破shift和pop等方法。 – Eirinn

9

我知道这是一个老问题,但我想我会扔我的答案有:

var u = ko.utils.unwrapObservable; 

ko.observableArray.fn.filter = function (predicate) { 
    var target = this; 

    var computed = ko.computed(function() { 
     return ko.utils.arrayFilter(target(), predicate); 
    }); 

    var observableArray = new ko.observableArray(u(computed)); 

    computed.subscribe(function (newValue) { observableArray(newValue); }); 

    return observableArray; 
}; 
10
self.masterList = ko.observableArray(); 
ko.computed(function() { 
    self.masterList(self.listA().concat(self.listB())); 
}); 

类似乔Flateau的在精神上的答案,但我倾向于认为这种方法是简单。

+0

我也是这么做的,但是这个问题仍然没有成为被接受的答案;因为任何更改都会导致绑定到'masterList'的任何视图被完全重绘? –

+0

@AdamLewis:是的,这确实重建了整个数组,并且依赖于视图引擎,它可能会或可能不会重新呈现整个DOM子图,因为它绑定了任何视图(不一定,尽管可能只是作出差异并应用它)。请注意,它可能仍然是避免许多更新的最佳解决方案。这不是我提到的有关你提到的答案的问题,如果视图引擎捕获数组属性本身(而不是它的路径),那么它将永远不会检测到你交换了数组(因为它是不可观察的)并且因此永远不会更新*。 – tne

+0

@tne我现在正在使用这个答案,但它似乎很慢...也许我在做别的错误。然而,这个解决方案是否打破了KO的预期目的?有没有另一种方法来解决需要计算可观察数组的问题?只是想知道这是否是在我的(或任何)情况下使用的正确工具。 – Nate

2

我不确定这是否是最有效的选择 - 但它非常简单,适用于我。所述ko.computed返回可观察到的阵列如下:

self.computedArrayValue = ko.computed(function() { 
    var all = ko.observableArray([]); 
    .... 
    return all(); 
}); 

代码的一个工作例子: HTML:

<div data-bind="foreach: days"> 
    <button class="btn btn-default btn-lg day" data-bind="text: $data, click: $root.dayPressed"></button>   
</div> 
上视图模型

Javascript函数:

self.days = ko.computed(function() { 
    var all = ko.observableArray([]); 
    var month = self.selectedMonth(); //observable 
    var year = self.selectedYear();  //observable 
    for (var i = 1; i < 29; i++) { 
     all.push(i); 
    } 
    if (month == "Feb" && year % 4 == 0) { 
     all.push(29); 
    } else if (["Jan","Mar","May","Jul","Aug","Oct","Dec"].find((p) => p == month)) { 
     [29,30,31].forEach((i) => all.push(i)); 
    } else if (month != "Feb") { 
     [29,30].forEach((i) => all.push(i));     
    } 
    return all(); 
}); 
相关问题