连接两个Knockout变量而不会导致递归

时间:2013-12-07 00:36:45

标签: javascript recursion binding knockout.js freeze

在为名为candy-calc的在线计算器框架开发代码时,我有两个ko.observables名为calcVar1.selUnitcalcVar2.selUnit,我希望将它们连接在一起。我的意思是,如果一个人改变,另一个人会改变,反之亦然。我试图解决这个问题的方法是创建两个显示变量calcVar1.dispSelUnit和calcVar2.dispSelUnit,它们是ko.computed()。它们在视图中绑定,并且它们具有不同的读/写功能,如下所示。

    // Modified write function  
     calcVar1.dispSelUnit = ko.computed({
        read : function(){
            console.log('Reading source var sel unit.');

            // Return as usual
            return calcVar1.selUnit();
        },
        write : function(value){
            // Write to both of them
            console.log('Writing ' + value + 'to both sel unit.');
            calcVar1.selUnit(value);
            calcVar2.selUnit(value);
        },
        owner : this
    });

    // Modified write function
    calcVar2.dispSelUnit = ko.computed({
        read : function(){
            console.log('Reading destination var sel unit.');

        // Make it equal to the source variables selected unit
            return calcVar2.selUnit();
        },
        write : function(value){
            // Write to both of them
            console.log('Writing ' + value + 'to both sel unit.');

            calcVar1.selUnit(value);
            calcVar2.selUnit(value);
        },
        owner : this
    });
}

基本上,dispSelUnits充当下面真实selUnit值的中介,并且在写入更新时selUnitko.observables),而在读取行为时像平常一样。

我看不出这个逻辑有什么问题。但是,在运行此操作时,如果我尝试更新compVar1.dispSelUnit,它会进入无限循环,其中compVar1.dispSelUnit被写入然后读取,然后compVar2.dispSelUnit被写入并读取,然后再返回。

1 个答案:

答案 0 :(得分:3)

我们也在Github(https://github.com/mbest/knockout-deferred-updates/issues/17)上讨论过这个问题。在查看他的代码之后,我做了以下观察和建议。

你得到了递归问题,因为这两个变量有value绑定到选择具有不同单位列表的框。虽然它们显示相同的单位,但它们实际上是不同的对象。 value绑定始终尝试将observable设置为列表中当前选定的项。但由于列表不同,这实际上是不可能的,并且可观察量在两个值之间无休止地切换。

要解决此问题,您需要两个选择框来引用相同的对象。在standard-resistance-finder.js中,执行以下操作:

var resistenceUnits = [
    new cc.unit('m\u2126', 0.001),
    new cc.unit('\u2126', 1.0),
    new cc.unit('k\u2126', 1000.0)
];

this.desiredRes = new cc.input(
    this,
    function() { return true; },
    resistenceUnits,
    0);

...

this.actualRes = new cc.output(
    this,
    ...
    resistenceUnits,
    0, 2);

关于保持两个可观察对象同步的问题,这个问题可能会提供一些答案:Simple, clean way to sync observables from different view models