在淘汰赛很多时候我都在下面的情况:KnockoutJS - 双向绑定适配器 - 避免循环
我有一个观察的,我想创造可观A和B之间的双向绑定适配器,也就是如果A的变化,改变B和当B的变化,然后改变A.
+-------------+ +-------------+ +-------------+ | A | -----> | Adapter | -----> | B | | Observable | <----- | | <----- | Observable | +-------------+ +-------------+ +-------------+
起初,这似乎是一个不这样做,因为这将创建一个循环依赖,但最终这究竟会发生什么时您将GUI元素绑定到observable。想象一下,你有一个现有的绑定,但你想改变它的绑定结果,而不必触摸绑定本身。
让我们看一个例子(jsfiddle here):
HTML:
<body>
<p data-bind="text: 'Value:' + val()"></p>
<input type="text" data-bind="textInput: val"></input>
<p data-bind="text: 'Value 2:' + val2()"></p>
<input type="text" data-bind="textInput: val2"></input>
</body>
的Javascript:
function ViewModel() {
var self = this;
this.val = ko.observable("");
this.val2 = ko.observable("");
this.val.subscribe(function() {
console.log("VAL Changed!");
self.val2(self.val().toUpperCase());
});
this.val2.subscribe(function() {
console.log("VAL2 Changed!");
self.val(self.val2().toLowerCase());
});
}
ko.applyBindings(new ViewModel());
你会发现,当你在输入的东西第一个文本框一个周期被触发:
个- 的结合变化VAL
- 的订阅VAL火灾和变化VAL2
- 的订阅VAL2火灾和改变VAL
- 敲除surpresses运行认购VAL再次(周期检测)
结果是,如果您在第一个输入框中键入一个大写字母,它将立即转换为小写字母,由第二个订阅,反之亦然。
虽然这个例子看起来不错,但它可能会导致很难找到错误。要解决现在的问题是一个简单的方法,有一个标志里面的绑定,这将避免升级时,我们是对方的更新里面:
....
var flag = false;
this.val.subscribe(function() {
if (flag) return;
flag = true;
self.val2(self.val().toUpperCase());
flag = false;
});
this.val2.subscribe(function() {
if (flag) return;
flag = true;
self.val(self.val2().toLowerCase());
flag = false;
});
....
现在当你改变第二个输入时,它不会“回火”,而只会朝一个方向发射。
现在终于我的问题:
是适配器无效用例和它暗示与代码的概念问题?
你会如何去防止气旋?有一个像我的例子中的国旗?也许使用throtteling?
这不能解决循环依赖的影响。如果你运行你的代码片段,你会意识到,当输入一个小写字母到第二个输入时,它将立即被第一次订阅反射转换为大写字母。 –
订阅不做任何转换。没有周期。当底层数据项发生变化时,两个计算的“读取”值都会改变,就这些了。 –
对不起 - 我没有花时间理解你的解决方案。所以你说有些情况下,“适配器”的两端只代表“一个”值。上述解决方案有所不同,它允许适配器的两端具有不同的状态,而在您的情况下,适配器的两端都只依赖一个状态“val”。这似乎比我更清洁,比马修斯的解决方案。你认为有可能出现两种状态的解决方案更适用的情况吗?我的大脑无法完全围绕它。 –