如何使用knockout.js管理和呈现嵌套数组?

时间:2012-03-17 18:24:34

标签: javascript knockout.js

我对Knockout.js很新,我现在正面临一种情况,我不确定如何正确处理它。问题是:我收到了一堆我正在通过ajax检索的对象。结果有点像这样:

var Objects = [ { id: 0, name: "Foo", type: "A" },
                { id: 1, name: "Bar", type: "B" },
                { id: 1, name: "Bar", type: "A" }, ... ];

到目前为止我所做的(简化):

var ViewModel = function() {
    var self = this;
    self.objects = ko.observableArray(Objects);
};

现在我需要根据它们的“类型”在不同的列表中渲染这些对象。所以有一个类型为“A”的对象列表和一个类型为“B”的对象列表等(目前有五种类型,但将来可能会增加一些类型)。

我已经提出了这个(工作)解决方案:

var ViewModel = function() {
    var self = this;
    self.objects = ko.observableArray(Objects);

    self.objectsA = ko.computed(function() {
        return ko.utils.arrayFilter(self.objects(), function(item) {
            return (item.type == 'A');
        });
    });

    self.objectsB = ...
    self.objectsC = ...
};

在我的实际观点中:

<h1>Type A</h1>
<ul class="typeA" data-bind="template: { name: 'object', foreach: objectsA }"></ul>

<h1>Type B</h1>
<ul class="typeB" data-bind="template: { name: 'object', foreach: objectsB }"></ul>

有没有更好的方法来解决这个问题?这很有效,但它有点难看,不是很有活力,而且包含很多重复。

2 个答案:

答案 0 :(得分:5)

绑定在computed observable内执行。这意味着如果您愿意,可以选择使用带参数而不是实际computed observable的简单函数。

这意味着您可以将其简化为:

var ViewModel = function() {
    var self = this;
    self.objects = ko.observableArray(Objects);

    self.filterByType = function(type) {
        return ko.utils.arrayFilter(self.objects(), function(item) {
            return (item.type === type);
        });
    };
};

然后,绑定它,如:

<h1>Type A</h1>
<ul class="typeA" data-bind="template: { name: 'object', foreach: filterByType('A') }"></ul>

<h1>Type B</h1>
<ul class="typeB" data-bind="template: { name: 'object', foreach: filterByType('B') }"></ul>

无论何时操作数组(添加/删除项目),您的UI都会立即更新。但是,如果您要动态编辑type,那么type将需要成为计算的observable更新的可观察对象(在您的原始方法中或以这种方式)。

此处示例:http://jsfiddle.net/rniemeyer/NFbxc/

答案 1 :(得分:1)

你可以让Knockout像这样进行过滤:

<h1>Type A</h1>
<ul class="typeA" data-bind="template: { name: 'object', foreach: objects }">
    <li data-bind="if: type = 'A'"><!--whatever mark-up you wanted here--></li>
</ul>

然后对其他类型做同样的事情。或者,您甚至可以让ViewModel保存一组类型,并使用一个模板完成所有操作。

编辑:包括RP Niemeyer的答案,你可以这样做:

var ViewModel = function() {
    var self = this;
    self.objects = ko.observableArray(Objects);
    self.types = ["A","B","C","D"];

    self.filterByType = function(type) {
        return ko.utils.arrayFilter(self.objects(), function(item) {
        return (item.type === type);
        });
    };
};

<!-- ko foreach types -->
    <h1> Type <span data-bind="text: $data"></h1>
    <ul data-bind="{attr: {class = 'type' + $data}, template: { name: 'object', foreach: filterByType($data)}}"></ul>
<!-- /ko -->

现在添加类型E很简单,就像在类型数组中添加“E”一样。