2013-04-10 74 views
8

看到工作的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); 

回答

4

稍微好一点的和有效的方式可能是这样的:

Working Fiddle

的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); 
     } 
    }); 
} 

希望它能帮助!

+0

优秀!谢谢 – Tsar 2013-04-15 08:10:38

+0

很酷。使他们在每次击键更新“afterkeydown''到字段的数据绑定属性:您可以添加'valueUpdate。 – 2013-11-11 10:30:09

5

一些评论到OP:

  • 你并不需要在ko.computedwrite方法return条款。
  • 您的方法在几个地方使用了​​函数,您可能想要更改该函数以获得特定的精度(或用于验证用户输入的集中位置)。所以你可以使用ko.extenders来改善。而且我会特别推荐由名为ko.extenders.numeric的ko团队制作的扩展器。
  • 您的方法在多个地方也使用console.log(),您可能需要使用由ko团队ko.extenders.logChange制作的另一个ko.extender。
  • 在这种情况下,我认为使用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目前接受的答案进行比较(这也相当不错和简单):我认为我的方法的主要优点是它可以让你使用这些超棒的扩展器。

+0

哦,'extenders'都很酷,尤其是事实,我可以加分观测到现有的观测 - 我的使用情况是大约渲染UI的专用件的错误信息,从不同的端点进来的(不是我的选择API架构)。 – 2017-02-20 09:41:30

0

不能承诺这将解决这个问题,但有时使延迟更新可以解决这样的问题。

这是一个很好的功能需要注意的,但要谨慎启用它已经运行的应用程序 - 并且如果你有一个潜在的问题,那么你还是会想解决这个问题。

http://knockoutjs.com/documentation/deferred-updates.html

+0

注:这是不一样的延期观察的 - 并且是从3.4.0开始一项新功能 – 2017-04-07 19:56:06