我有一个采购订单模型。采购订单包含行项目。 订单项有预算。
现在每当用户从预算下拉列表中选择预算时,使用kncokoutjs我想从服务器加载预算剩余金额,然后如果项目使用预算并在项目下显示,则重新计算该预算的剩余金额。 / p>
我的问题是如何设计模型,以便我可以捕获在项目上选择的预算并计算剩余金额。
答案 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;