Как рассчитать итог в сетке с расширенными объектами breeze.js?

Я работаю над веб-приложением MVC, используя шаблон MVVM, breeze.js и Knockout.js. Я впервые использую эти js-библиотеки, и мне еще предстоит понять, как они работают.

На одной из страниц приложения есть сетка, в которой столбцы и строки генерируются динамически. Мне нужно добавить дополнительный столбец, где для каждой строки у меня есть общее количество значений, отображаемых в следующих ячейках строки. Вот пример:

Data type |   Comment   |  Fact 1 | Fact 2 |  Total    | Value 1 | Value 2 | Value 3 | Value 4
==============================================================================================
Item 1    | any comment |  fact 1 | fact 2 | calc. sum |    10   |   20    |    30   |   40

Сетка создается путем привязки объекта сущности бриза (planningItems) к шаблонам. Объект имеет свойства DataTypeId, Comment, Member, Total, FactValues. Итого – рассчитанная сумма.

<script type="text/html" id="list-planning-template">
<tr data-bind="mouseOverButton: $data">
    <td style="text-align: center">
        <button class="actionbutton actionbutton-item" data-bind="selectItem: $root.selectedItems, itemId: FactId"></button>
    </td>
    <td data-bind="text: DataTypeId" />
    <td data-bind="text: Comment().Text" />
    <!-- ko foreach: FactMembers -->
    <td data-bind="text: Member().Code"></td>
    <!-- /ko -->
    <td data-bind="text: Total" />
    <!-- ko foreach: FactValues -->
    <td style="width: 50px" data-bind="text: Value"></td>
    <!-- /ko -->
</tr>

I have been trying to add the Total property by extending the breeze entity object in the following way:

var FactCtor = function () {
this.Total = ko.computed({
    read: function () {
        var sum = 0;
        if (this.FactValues) {
            this.FactValues().forEach(function (fv) {
                sum += fv.Value();
            });
        }
        return sum;
    },
    deferEvaluation: true
}, this);
};

manager.metadataStore.registerEntityTypeCtor("Fact", FactCtor);

По сути, этот код должен расширять сущность, добавляя нокаутирующий вычисляемый наблюдаемый объект с именем Total с отложенной оценкой. Функция перебирает наблюдаемый бризом массив FactValues ​​и добавляет значения. Я безрезультатно копался в разных версиях этого кода. Кто-нибудь может подсказать, что не так с этим кодом?


person Marco    schedule 14.12.2012    source источник
comment
Мое подозрение состоит в том, что вычисление не вызывается изменениями в массиве или его содержимом. Вычисление запускается только при изменении самого свойства FactValues. FactValues - это массив. Это всегда один и тот же массив, даже если содержимое массива изменяется. Я просто предполагаю, как я сказал. Если моя догадка верна, есть путь вперед … путем прослушивания изменений в массиве (добавления/удаления) и запуска обновления вычислений, когда значения приходят или уходят. Вы можете попробовать это. В данный момент я завален, но если кто-то не решил это за день или около того, я отдам ему любовь.   -  person Ward    schedule 15.12.2012
comment
Спасибо за ответ, Уорд. Мы смогли преодолеть проблему, используя пользовательскую привязку. Подробности смотрите в моем следующем посте.   -  person Marco    schedule 18.12.2012


Ответы (2)


ОБНОВЛЕНИЕ:

Нам не удалось заставить код, опубликованный в моем предыдущем посте, работать. В конечном итоге мы смогли решить эту проблему, используя пользовательскую привязку с ветерком. Вот код:

   ko.bindingHandlers.getFyTotal = {
   update: function (element, valueAccessor) {
       var sum = 0;
       var fact = valueAccessor();
       if (fact.FactValues()) {
           fact.FactValues().forEach(function (fv) {
               sum += parseFloat(fv.Value());
           });
       }

       $(element).html(sum);
   }
};

Затем пользовательская привязка упоминается в коде HTML следующим образом:

<td data-bind="getFyTotal: $data" />

Надеюсь, это может помочь другим.

ИСПРАВЛЕННАЯ ВЕРСИЯ:

Мы обновили приведенный выше код, чтобы воспользоваться функциями ko.utils:

ko.bindingHandlers.getFyTotal = {
update: function (element, valueAccessor) {
    var sum = 0;
    var fact = valueAccessor();
    if (fact.FactValues()) {
        ko.utils.arrayForEach(fact.FactValues(), function (fv) {
            sum += parseFloat(fv.Value());
        });
    }

    $(element).html(sum);
  }
};
person Marco    schedule 18.12.2012

Я смоделировал ваш код вне Breeze, и он работает:

http://jsfiddle.net/DazWilkin/yGZ7g/7/

Я сделал небольшую настройку, добавив ссылку на FactValues ​​(observableArray) в ваш конструктор, чтобы преодолеть то, что, как я полагаю, является зацикливанием/этой проблемой в JavaScript.

Однако я не пробовал это в Breeze и хотел сделать что-то подобное. Мне не удалось заставить работать аналогичную функцию, и в конечном итоге я создал итоги во время обработки «затем» моего executeQuery:

...manager.executeQuery(....).then(function(data) {
   ...
   Fact.Total(FactValues()
      .map(function(fv){ return fv.Value(); })
      .reduce(function (total,curr) { return total+curr; });
   ...
}

Я постараюсь вернуться к работе над своей версией сегодня и, если найду лучшее решение, отчитаюсь.

person DazWilkin    schedule 14.12.2012
comment
Спасибо за ваш ответ, DazWilkin. Интересно, что код работает для вас. В нашем случае он терпит неудачу, когда ветер пытается запросить данные. В конце концов мы решили проблему, используя пользовательскую привязку с ветерком. Смотрите обновление в моем исходном посте для деталей. - person Marco; 18.12.2012