KnockoutJS计算不计算(或更新)

时间:2018-06-12 15:47:15

标签: knockout.js computed-observable

在某些情况下,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字段才会更新。

我的问题

  1. 为什么dozens输入仍然显示dozens,即使1.5函数的返回值是空字符串?我可以在read()内部或之后强制使用新read()或以其他方式强制更新用户界面吗?

  2. 我假设即使在更改write()输入的值后dozens输入未更新的原因,也是{{pieces输入的结果1}}函数将是连续两次的空字符串,并且KnockoutJS在内部缓存此值并发现它没有被更改。同样,我如何强制输入更新?

1 个答案:

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