1

我正在使用 MVVM 模式、breeze.js 和 knockout.js 开发一个 MVC Web 应用程序。这是我第一次使用这些 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。Total 是计算的总和。

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

我一直在尝试通过以下方式扩展微风实体对象来添加 Total 属性:

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 的淘汰计算 observable 和延迟评估来扩展实体。该函数遍历微风可观察数组 FactValues 并添加值。我一直在研究这段代码的不同版本,但无济于事。谁能给我这个代码有什么问题的提示?

4

2 回答 2

1

更新:

我们无法让我之前帖子中发布的代码正常工作。我们最终能够通过使用带有微风的自定义绑定来克服这个问题。这是代码:

   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);
  }
};
于 2012-12-18T10:04:56.777 回答
0

我在 Breeze 之外对您的代码进行了建模,并且可以正常工作:

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

我做了一个小调整,在你的构造函数上添加了对 FactValues (observableArray) 的引用,以克服 - 我相信 - JavaScript 中的循环/这个问题。

但是,我还没有在 Breeze 中尝试过这个并且想做类似的事情。我无法使类似的功能正常工作,并最终在我的 executeQuery 的“then”处理期间创建了总数:

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

我将尝试回到我今天的版本,如果我找到更好的解决方案,我会报告回来。

于 2012-12-14T17:41:28.073 回答