2012-03-17 29 views
1

我对Knockout.js很陌生,现在面临的情况是我不确定如何处理它。问题是:我收到了一堆我通过ajax检索的对象。其结果将是有点像这样:如何使用knockout.js管理和呈现嵌套数组?

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> 

有没有更好的办法来解决这个问题呢?这有效,但它有点难看,并不真正动态,并且包含很多重复。

回答

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作为要更新的计算可观察值的观察值(以您的原始方法或以此方式进行更新)。

样品在这里:http://jsfiddle.net/rniemeyer/NFbxc/

+0

谢谢,这使得更清晰。我要去这个! – Niko 2012-03-17 18:46:21

1

你可以只让淘汰赛做过滤这样的:

<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尼迈耶的答案,你可以这样做:

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”到你的类型数组。

+0

你的意思是,像两个嵌套的foreach循环?那可能吗? – Niko 2012-03-17 18:43:24

+0

@妮科:是的。有可能的 – 2012-03-17 19:30:28