[英]Circular dependency of knockout computed
看工作jsFiddle: http : //jsfiddle.net/ruslans/vFK82/
我有3個字段:凈價(除稅),稅額和總價(價格除了增值稅+稅額)。 NetPrice和Total是可寫的,即您可以更改其中任何一個,並且必須自動計算其他2個值。
我這樣做的方法是使用3個可觀察和2個計算的淘汰對象,但我想也許有人知道Knockout好多了可能會提出一種更有效的方法來實現這一目標。
HTML:
Net Price:
<input type="textbox" data-bind="value: NetPriceCalc" />
<br />Tax Amount:
<label data-bind="html: TaxAmt"></label>
<br />Total:
<input type="textbox" data-bind="value: TotalCalc" />
腳本:
var viewModel = {
NetPrice: ko.observable(100),
TaxAmt: ko.observable(20),
Total: ko.observable(120),
TaxRate: 0.2
};
viewModel.updateTaxAmt = function (useNetPrice) {
if (useNetPrice) {
return this.TaxAmt(this.NetPrice() * this.TaxRate);
} else {
var total = Number(this.Total());
var taxAmt = total - total / (1 + this.TaxRate);
return this.TaxAmt(taxAmt);
}
};
viewModel.updateNetPrice = function () {
this.NetPrice(Number(this.Total()) - Number(this.TaxAmt()));
};
viewModel.updateTotal = function () {
this.Total(Number(this.NetPrice()) + Number(this.TaxAmt()));
};
viewModel.NetPriceCalc = ko.computed({
read: function () {
console.log("NetPriceCalc read");
return viewModel.NetPrice();
},
write: function (value) {
console.log("NetPriceCalc write");
viewModel.NetPrice(value);
viewModel.updateTaxAmt(true);
return viewModel.updateTotal();
}
});
viewModel.TotalCalc = ko.computed({
read: function () {
console.log("TotalCalc read");
return viewModel.Total();
},
write: function (value) {
console.log("TotalCalc write");
viewModel.Total(value);
viewModel.updateTaxAmt(false);
return viewModel.updateNetPrice();
}
});
ko.applyBindings(viewModel);
對OP的一些評論:
ko.computed
的write
方法中的return
子句。 Number()
函數,您可能希望更改它以獲得特定的精度(或用於驗證用戶輸入的某個集中位置)。 所以你可以使用ko.extenders來改進它。 我特別推薦已經由名為ko.extenders.numeric
的ko團隊制作的擴展器。 console.log()
,你可能想要使用ko團隊ko.extenders.logChange
制作的另一個ko.extenders.logChange
。 subscribe
更好,而不是ko.computed
,因為它將花費更少的代碼(並且可能微不足道地更快)。 我的方法是:
function viewModel() {
this.TaxRate = 0.2;
this.NetPrice = ko.observable().extend({ numeric: 2, logChange: "NetPrice" });
this.TaxAmt = ko.observable().extend({ numeric: 2, logChange: "TaxAmt" });
this.Total = ko.observable().extend({ numeric: 2, logChange: "Total" });
this.NetPrice.subscribe(function (newNetPrice) {
this.TaxAmt(newNetPrice * this.TaxRate);
this.Total(newNetPrice + this.TaxAmt());
}, this);
this.Total.subscribe(function (newTotal) {
this.TaxAmt(newTotal - newTotal / (1 + this.TaxRate));
this.NetPrice(newTotal - this.TaxAmt());
}, this);
this.NetPrice(100);
}
// then I have the extenders code copied exactly as seen in: http://knockoutjs.com/documentation/extenders.html)
ko.extenders.numeric = ...
ko.extenders.logChange = ...
// and finally init everything as usual
ko.applyBindings(new viewModel());
你可以在這里看到工作小提琴: http : //jsfiddle.net/protron/JFPgu/2/
請注意此解決方案中的數字如何不會比數字擴展器上指定的數字更多(即使用戶輸入的值自動固定為所需的精度)。
並將我的回答與gaurav當前接受的答案進行比較(這也非常簡單):我認為我的方法的主要優點是它可以讓你使用這些令人敬畏的擴展器。
一個稍微好一點的方法可能是這樣的:
HTML
Net Price:
<input type="textbox" data-bind="value: NetPrice" />
<br />Tax Amount:
<label data-bind="html: TaxAmt"></label>
<br />Total:
<input type="textbox" data-bind="value: Total" />
JS
function viewModel() {
var self = this;
self.NetPrice = ko.observable(100);
self.TaxRate = 0.2;
self.TaxAmt = ko.computed(function() {
return parseFloat(self.NetPrice()) * self.TaxRate;
});
self.Total = ko.computed({
read: function() {
return parseFloat(self.NetPrice()) + self.TaxAmt();
},
write: function(val){
var total = parseFloat(val);
var taxAmt = total - total / (1 + self.TaxRate);
self.NetPrice(total - taxAmt);
}
});
}
希望能幫助到你!
不能保證這會解決問題,但有時啟用延期更新可以解決這樣的問題。
這是一個很好的功能,但要注意為已經運行的應用程序啟用它 - 如果你確實有一個潛在的問題,那么你仍然想要解決這個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.