Knockout计算可观察数组的项目

时间:2017-01-31 07:51:52

标签: javascript knockout.js

我有以下ViewModel:

$.each(myViewModel.categories(), function(index, cat){
  cat.num = ko.computed(function(){
    return cat.items().length;
  }, cat);
});

我想为这个数组的每个项添加一个计算值:

<ul data-bind="foreach: { data: categories, as: 'category' }">
    <li>
        <ul data-bind="foreach: { data: items, as: 'item' }">
            <li>
                <span data-bind="text: category.name"></span>:
                <span data-bind="text: item"></span>
            </li> 
        </ul>
      <span data-bind="text: category.num"></span>
    </li>
</ul>

这是我的HTML:

Fruit: Apple
Fruit: Orange
Fruit: Banana
3

它的效果非常好!结果如下:

myViewModel.categories([
  {
    name: "Fruit",
    items: ["Apple", "Banana"],
  },
  {
    name: "Veg",
    items: ["Potato", "Carridge"],
  }
]);

但现在让我们说我的数据发生了变化,我需要反映这些变化:

num

它不起作用 - 我不会在每个列表的末尾看到//First remove the current formatters config.Formatters.Clear(); //Then add the json formatter config.Formatters.Add(new JsonMediaTypeFormatter()); 。你能帮我解决这个问题吗?这是codepen

1 个答案:

答案 0 :(得分:2)

当然它不起作用,因为您要替换observableArray的全部内容。你的代码:

$.each(myViewModel.categories(), function(index, cat){
    cat.num = ko.computed(function(){
        return cat.items().length;
    }, cat);
});

num属性添加到调用时数组中存在的项目。通过执行以下操作为observableArray提供新的后备阵列:

myViewModel.categories([
  {
    name: "Fruit",
    items: ["Apple", "Banana"],
  },
  {
    name: "Veg",
    items: ["Potato", "Carridge"],
  }
])
当然,你丢失了旧数组,因此丢失了在项上定义的而不是可观察数组的计算observable。 Knockout当然无法知道如何以及是否应该将计算属性添加到新数组中的每个项目。

解决方案:

当您替换observableArray的支持数组时,您可以执行相同的属性添加:

myViewModel.categories([
  {
    name: "Fruit",
    items: ["Apple", "Banana"],
  },
  {
    name: "Veg",
    items: ["Potato", "Carridge"],
  }
]);
$.each(myViewModel.categories(), function(index, cat){
    cat.num = ko.computed(function(){
        return cat.items().length;
    }, cat);
});

或者更好的是,您可以使用已定义的属性实例化数组中的对象。注意:您不必为每个项目反复编写函数,例如,您可以为数组项定义构造函数:

function Category(name, items) {
  var self = this;

  this.name = name;
  this.items = ko.observableArray(items);
  this.num = ko.computed(function() {
    return self.items().length;
  });
};

然后,这是你创建一个新的方法:

var newItem = new Category('Category 1', [ 'Apple', 'Banana']);

并将其插入可观察数组:

myViewModel.categories.push(newItem);

这会添加一个项目并保留现有项目,或者像您一样,您可以提供一个全新的数组:

myViewModel.categories([
  new Category('Fruit', ['Apple', 'Banana' ]),
  new Category('Veg', ['Potato', 'Carridge' ])
]);