Knockout - Как настроить вычисляемые свойства для дочерних и родительских элементов одновременно? - PullRequest
3 голосов
/ 09 февраля 2012

У меня есть коллекция предметов, которые я хотел бы отобразить как общее, так и индивидуальное процентное содержание каждого предмета.Кажется, проблема в том, что мне нужна ссылка на родительский объект при вычислении суммы.Поэтому я решил определить вычисленный 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);

И мой HTML-код

    <ul data-bind="foreach: parts">
    <li>
        <p data-bind="text: amount"></p>
        <p data-bind="text: percentage"></p>
    </li>
</ul>

Однако Collection.parts всегда пуст,По какой-то причине нажмите на нее, не вызывая пересчеты элементов.

И правильно ли это делать?Теперь я могу понять, как можно одновременно создать массив observableArray в коллекции, в то же время давая каждому дочернему элементу ссылку на родительский объект.

1 Ответ

6 голосов
/ 09 февраля 2012
  1. Ваш getTotal должен возвращать сумму сумм, а не количество деталей, верно?
  2. Вам не нужно вставлять элементы в детали по одной.Вы можете сделать collection.parts ($. Map ([40, 50, 30], function (el) {вернуть новую 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);
});

Html:

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