如何计算Knockoutjs

时间:2017-02-07 10:18:46

标签: javascript knockout.js

我有一个采购订单模型。采购订单包含行项目。 订单项有预算。

现在每当用户从预算下拉列表中选择预算时,使用kncokoutjs我想从服务器加载预算剩余金额,然后如果项目使用预算并在项目下显示,则重新计算该预算的剩余金额。 / p>

我的问题是如何设计模型,以便我可以捕获在项目上选择的预算并计算剩余金额。

enter image description here

1 个答案:

答案 0 :(得分:0)

为PurchaseOrder,Item和Budget制作不同的ViewModel。 使用计算值计算金额 并使用计算机来处理ui(例如可能的预算)。

(见http://knockoutjs.com/documentation/computedObservables.html

代码段中的代码示例:(编辑:可以多次使用预算的已实施要求)



// class for a budget
function Budget(purchaseOrder, name, amount) {
  // track the purchaseOrder object to be able to find the budgets that can be used
  var self = this;
  this.purchaseOrder = purchaseOrder
  this.name = name;

  // amount as an observable so it can be updated from the latest server state
  this.amount = ko.observable(amount);

  this.usedByItems = ko.pureComputed(function() {
    var returnValue = 0;
    self.purchaseOrder.items().forEach(function(item) {

      if (item.budget() === self && item.amount()) {
        // note:better type conversion required
        returnValue = returnValue + parseInt(item.amount());
      }


    });
    return returnValue;
  }, this);

  this.remaining = ko.pureComputed(function() {
    return this.amount() - this.usedByItems();
  }, this);

  // use a computed to determine if the budget is used
  // in the final solutions, computed can be used in the budget dropdown to select only unused budgets
  this.used = ko.pureComputed(function() {
    return this.purchaseOrder.isBudgetUsed(this);
  }, this);
}

// class for an item
function Item(purchaseOrder, budget) {

  var self = this;

  // track the purchase order to track the selectable budgets for the dropdown
  this.purchaseOrder = purchaseOrder;

  // computes the selectable budgets
  this.selectableBudgets = ko.pureComputed(function() {
    var returnValue = [];
    self.purchaseOrder.budgets.forEach(function(budget) {
      // add buget if the item's budget is the same, this to prevent budgets
      // magically disappearing from the dropdown
      if (budget === self.budget() || budget.remaining() > 0) {
        returnValue.push(budget);
      }
    });


    return returnValue;
  }, this);

  // computed to habdle a name when a budget is not selected
  this.name = ko.pureComputed(function() {
    if (this.budget()) {
      return this.budget().name;
    } else {
      return "(none)";
    }

  }, this);
  // the related budget
  this.budget = ko.observable(budget);

  // the entered amount
  this.amount = ko.observable();

}


// the main viewmodel
function PurchaseOrderViewModel() {
  // define the budgets, in the final situation it would probably an observable array so more budgets can be added
  this.budgets = [
    new Budget(this, "Budget 1", 20),
    new Budget(this, "Budget 2", 30),
    new Budget(this, "Budget 3", 40)
  ];

  // the items for the purchase order
  this.items = ko.observableArray(
    [
      new Item(this, this.budgets[0]),
      new Item(this, this.budgets[2]),
    ]
  );

  var self = this;



  this.addItem = function() {
    var item = new Item(self);
    self.items.push(item);
  }

  this.remove = function(item) {
    self.items.remove(item);

  }

  // determins if there is an item that uses the budget.
  this.isBudgetUsed = function(budget) {
    var returnValue = false;
    self.items().forEach(function(item) {
      if (item.budget() === budget) {
        returnValue = true;
      }
    });

    return returnValue;
  }
}

ko.applyBindings(new PurchaseOrderViewModel());

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 

<h1>
Items
</h1>
<ul data-bind="foreach:items">
  <li>
    <select data-bind="options:selectableBudgets,optionsText:'name',value:budget,optionsCaption:'(select a budget)'">

    </select>
    <span data-bind="text:name"></span>
    <input data-bind="value:amount" type="number" />
    <a href="javascript:void();" data-bind="click:function(){ $parent.remove($data);}">remove</a>
  </li>
</ul>
<a href="javascript:void();" data-bind="click:addItem">add item</a>

<h1>
Budget
</h1>
<ul data-bind="foreach:budgets">
  <li>

    <span data-bind="text:name"></span> #<span data-bind="text:amount"></span>, used in po:<span data-bind="text:used"></span>, amount used:<span data-bind="text:usedByItems"></span>, remaining:<span data-bind="text:remaining"></span></li>
</ul>
&#13;
&#13;
&#13;