Knockout - 如何同时设置子和父的计算属性?

Cod*_*ave 3 javascript data-binding mvvm knockout.js

我有一个项目集合,我想显示每个项目的总数和个别百分比.问题似乎是我在计算总数时需要父对象的引用.所以我想我会定义Collection的计算getTotal和项目的百分比.

    function Collection() {
    var self = this;
    self.parts = ko.observableArray();
    self.getTotal = ko.computed(function() {
        var total = self.parts.length;
        return total;
    });
}

function Part(amount, parent) {
    var self = this;
    self.amount = ko.observable(amount);
    self.parent = parent;

    self.percentage = ko.computed(function() {
        return self.amount() / self.parent.getTotal();
    });
}

var partsData = [40, 50, 30];
var collection = new Collection();
for (var i = 0; i < partsData.length; ++i) {
    collection.parts.push(new Part(partsData[i], collection));
}

ko.applyBindings(collection);
Run Code Online (Sandbox Code Playgroud)

我的HTML是

    <ul data-bind="foreach: parts">
    <li>
        <p data-bind="text: amount"></p>
        <p data-bind="text: percentage"></p>
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

但是Collection.parts总是空的.由于某种原因,推动它不会触发重新计算的项目.

这也是正确的方法吗?我现在可以弄清楚如何在Collection中同时创建一个observableArray,同时为每个子项提供对父对象的引用.

Rom*_*aev 6

  1. 你的getTotal应该返回金额的总和,而不是零件的数量,对吧?
  2. 您不必逐个将元素推送到零件.你可以做collection.parts($.map([40,50,30],function(el){return new Part(el,collection);});)(我在这里使用jQuery.map)
  3. 一般来说,我认为百分比不属于Part,因为它必须传递一个集合,这是不好的(不必要的依赖).我会这样做:
function ViewModel() {
    var self = this;
    self.parts = ko.observableArray([]);
    self.total = ko.computed(function(){
        var s = 0;
        $.each(self.parts(), function(i, el){s += el.amount();});
        return s;
    });
}

function Part(amount){
    this.amount = ko.observable(amount);
}

$(function() {
    var view = new ViewModel();
    var parts = $.map([40, 50, 30], function(el){return new Part(el);});
    view.parts(parts);
    ko.applyBindings(view);
});
Run Code Online (Sandbox Code Playgroud)

HTML:

<ul data-bind="foreach: parts()">
    <li>
        <p data-bind="text: amount"></p>
        <p data-bind="text: amount() / $root.total()"></p>
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)