淘汰赛的循环依赖计算(Circular dependency of knockout compute

2019-08-21 05:23发布

看到工作的jsfiddle: http://jsfiddle.net/ruslans/vFK82/

我有3个领域:净价(前含税),纳税额和总价格(价格不含税+税额。)。 在NetPrice和达尔可写的,即你可以改变任何他们与其他2个值必须是自动计算。

我已经做到了使用3个观察到的,(2)计算淘汰赛对象,但我想也许别人谁知道淘汰赛好了很多,可能表明一个更有效的方式来实现这一目标的方式。

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

Answer 1:

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

工作小提琴

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

希望能帮助到你!



Answer 2:

一些评论到OP:

  • 你不需要return的条款write该法ko.computed
  • 你的方法使用的Number()上的多个地点功能,你可能想改变,为了得到一个特定的精度(或用户输入的验证一些集中的地方)。 所以,你可以使用ko.extenders来改善这一点。 而且我特别建议已经被KO队命名所作的扩展ko.extenders.numeric
  • 你的方法也使用console.log()在几个地方,你可能希望使用由KO队取得另一ko.extender ko.extenders.logChange
  • 取而代之的是ko.computed在这种情况下,我认为这是更好地使用subscribe ,因为这将需要更少的代码(也可能不明显更快)。

我的做法是这样的:

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/

注意在该溶液中的电话号码如何永远不会有更多的小数比上的数字增量剂(即使由用户输入的值被自动地固定在所期望的精确度)的指定。

而我的答案比较由拉夫目前公认的答案(这也是相当不错的,简单):我觉得我的方法的主要优点是,它可以让你使用这些真棒扩展。



Answer 3:

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

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

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



文章来源: Circular dependency of knockout computed