在某些情况下,ko.computed
即使其绑定的ko.observable
发生更改也不会更新。我想知道为什么,我做错了什么以及我应该做些什么。
示例
考虑这个简单的打击转换器(JSFiddle here)。
HTML 的
<label>Dozen:</label><br>
<input type="number" data-bind="value: dozen">
<span class="error" data-bind="text: error"></span><br>
<label>Pieces:</label><br>
<input type="number" data-bind="value: pieces"><br>
的JavaScript
function ViewModel() {
var self = this;
self.error = ko.observable('');
self.pieces = ko.observable('');
self.dozen = ko.computed({
read: function() {
var p = parseInt(self.pieces(), 10);
if (!p) return '';
if (p % 12 === 0) return p / 12;
else return '';
},
write: function(value) {
if (/\D/.test(value)) {
self.error('Only whole numbers');
} else {
self.error('');
if (value) self.pieces(value * 12);
}
}
});
}
ko.applyBindings(new ViewModel());
它的作用
它将显示两个输入。一个允许你输入几十个(例如2个),另一个将显示多少个(24)。
您还可以输入多个部分(例如36个),转换器将显示有多少个(3)。
如果您在pieces
框中输入的内容不能被12整除,则会清除dozens
输入,表明该数字不是十几个。同样,我们也不允许用户输入几十个。
工作原理
dozens
输入绑定到KnockoutJS computed observable。它不具备它自己的价值(也许它在幕后,但这是我所不知道的)但是是从pieces
属性计算的,这是一个常规的observable。要获得数十个,这些部分除以12,如果结果是整数,则返回,否则返回空字符串。
问题
启动计算器,然后在1.5
输入中输入dozens
。计算器将通知您不允许小数。 pieces
字段将保持原样不变。但是,dozens
输入不会被清除以反映pieces
字段的值。
然后在pieces
输入中输入新值,例如18
。此应该清除dozens
输入(因为它是computed
,仅取决于视图模型的pieces
属性,并且此值已更改),< em>但它没有。
值1.5
一直显示在dozens
字段中,即使read()
的{{1}}函数永远不会返回这样的小数。 computed
绑定的observable
已更新,但computed
无法计算。
只有在computed
字段中输入可被12整除的数字时,pieces
字段才会更新。
我的问题
为什么dozens
输入仍然显示dozens
,即使1.5
函数的返回值是空字符串?我可以在read()
内部或之后强制使用新read()
或以其他方式强制更新用户界面吗?
我假设即使在更改write()
输入的值后dozens
输入未更新的原因,也是{{pieces
输入的结果1}}函数将是连续两次的空字符串,并且KnockoutJS在内部缓存此值并发现它没有被更改。同样,我如何强制输入更新?
答案 0 :(得分:1)
输入保持显示1.5,因为UI和模型不同步。模型未收到任何更改,因为值为且始终为空字符串。当输入1.5时,写入函数将中止而不向模型写入任何值,因此就模型而言,值仍为空。然后,当再次为Pieces输入18时,该函数返回一个空字符串,如您所猜测的那样没有注册为更改。
您可以使用这个小宝石强制计算出的函数再次更新UI:computed.notifySubscribers()
write: function(value) {
if (/\D/.test(value)) {
self.error('Only whole numbers');
self.dozen.notifySubscribers(); //<--- here
} else {
self.error('');
if (value) self.pieces(value * 12);
}
}