我想解决knockout.js中的以下问题:我有三个输入;我需要设置的price
,quantity
和total
total = price * quantity
我更新price
或quantity
时,我也想设置
price = total / quantity
如果我更新total
。
我最初使用计算的observable来做这个,但是这几乎只能工作,但是我有一个舍入问题。例如。如果我做
quantity(3)
total(100)
我希望price
设置为33.33,只有两位小数,而total
仍应设置为100,因此标识total = price * quantity
并不完全成立。
在我采用的计算可观察方法中,total
在这种情况下将设置为99.99。 这就是使这种情况与文档中的fullname / firstname / lastname示例不同的原因。
基本上price
/ total
字段是相互递归的。除了手动订阅之外,我找不到解决这个问题的好方法,但这感觉非常单一,并且意味着我必须手动处理一堆订阅等。
答案 0 :(得分:3)
我通过制作“真正有价值”的ko.observables(即数量,价格和总数),在表单字段上跟踪焦点事件,并使用ko.computed()重新计算(但不是如果选择了当前字段)并格式化表单的值。
一句话描述听起来很复杂,但代码并不复杂。
JavaScript的:
var Model = function () {
var self = this;
self.quantity = ko.observable(0);
self.price = ko.observable(0);
self.price.selected = ko.observable(false);
self.total = ko.observable(0);
self.total.selected = ko.observable(false);
self.formattedPrice = ko.computed({
read: function () {
if (!self.price.selected()) {
var total = self.total() || 0;
var quantity = self.quantity() || 0;
var value = total / quantity;
self.price(isNaN(value) ? 0 : value);
}
return '$' + self.price().toFixed(2);
},
write: function (value) {
value = parseFloat(value.replace(/[^\.\d]/g, ""));
self.price(isNaN(value) ? 0 : value);
}
});
self.formattedTotal = ko.computed({
read: function () {
if (!self.total.selected()) {
var quantity = self.quantity() || 0;
var price = self.price() || 0;
var value = quantity * price;
self.total(isNaN(value) ? 0 : value);
}
return '$' + self.total().toFixed(2);
},
write: function (value) {
value = parseFloat(value.replace(/[^\.\d]/g, ""));
self.total(isNaN(value) ? 0 : value);
}
});
};
ko.applyBindings(new Model());
在HTML中,您可以像这样绑定价格和总数:
<input data-bind="value: formattedPrice, hasfocus: price.selected" />
<input data-bind="value: formattedTotal, hasfocus: total.selected" />
jsfiddle处的代码,如果您想查看一个有效的示例。
答案 1 :(得分:0)
感谢您的回答。仅供参考,这是我目前的解决方案,可能会坚持下去,除非它给我带来麻烦。
var self = this;
this.price = ko.observable().extend({numeric: 2});
this.quantity = ko.observable(1).extend({ numeric: 2 });
this.total = ko.observable(1).extend({ numeric: 2 });
var unsub_total = this.total.subscribe(function (total) {
if (self.quantity() != 0)
self.price(total / self.quantity())
});
// setting quantity will update both price and total
var unsub_qty = this.quantity.subscribe(function (qty) {
self.total(self.price() * qty);
});
var unsub_price = this.price.subscribe(function (price) {
self.total(price * self.quantity());
});
this.unsub = function() { unsub_total(); unsub_price(); unsub_qty(); };