javascript - 可观察数组的 knockout 计算项

标签 javascript knockout.js

我有以下 View 模型:

var myViewModel = {
  categories: ko.observableArray([
    { name: ko.observable('Fruit'), 
      items: ko.observableArray([ 
        ko.observable('Apple'),
        ko.observable('Orange'), 
        ko.observable('Banana'), 
      ]),
    },
  ]),
};

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

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

这是我的 HTML:

<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>

而且效果很好!这是结果:

Fruit: Apple
Fruit: Orange
Fruit: Banana
3

但现在假设我的数据发生了变化,我需要反射(reflect)这些变化:

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

它不起作用 - 我没有在每个列表的末尾看到 num。你能帮我解决这个问题吗?这是 codepen

最佳答案

当然这是行不通的,因为你正在替换 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"],
  }
])

当然,您丢失了旧数组,因此丢失了在项目上定义的计算可观察值,而不是可观察数组。 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' ])
]);

关于javascript - 可观察数组的 knockout 计算项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41952307/

相关文章:

javascript - 通过 Javascript 验证表单字段

knockout.js - 调用默认 knockout 绑定(bind)时自定义 knockout 绑定(bind)失败

knockout.js - 如何防止在执行 knockout 绑定(bind)之前显示 Html

javascript - 在没有浏览器滚动的情况下,div 比浏览器宽

javascript - Qunit+SinonJs spy.calledOnce in setTimeout is undefined

javascript - Angular 2 Facebook 登录

design-patterns - 带有 Backbone、API 设计理念的基于事件的权限?

javascript - 显示比较表

javascript - Knockout.js 如何从绑定(bind)构建字符串

javascript - 什么时候真正需要基于文件名的浏览器缓存清除?