4

我对 KO 比较陌生(两天前开始)并且正在尝试一些简单的例子。目前,我对这段代码有疑问。

<div id="idChangeStyle">
    <span data-bind="style: { background: GetAge() < 18 ? 'red':'white'}">Enter Your Age:</span>
    <input type="text" data-bind="value: GetAge"></input>
</div>
function ageViewModel() {
    var self = this;
    self.age = ko.observable(18);
    self.GetAge = ko.computed({
        read: function () {
            return self.age();
        },
        write: function (value) {
            value = parseInt(String(value).replace(/[^\d]/g, ""));
            if (isNaN(value))
                self.age(18);
            else
                self.age(value);
        }
    });
};
ko.applyBindings(new ageViewModel(), document.getElementById('idChangeStyle'));

http://jsfiddle.net/WJZqj/

基本上,该应用程序采用单个输入(年龄)。我正在使用可写计算 observable 来解析 INTEGER 的输入,并在解析其 NaN 后,我试图将年龄设置为其默认值,即 18。此外,我在 html 上有一个简单的逻辑,我将 span 的背景更改为红色如果年龄低于 18 岁。

在正常情况下它工作正常,这是我遇到问题的时候: -

Case 1:
Current Input: 18 (initial case) 
enter *4* then tab //works
enter *a* then tab //work (defaults to 18) 
enter *a* then tab //doesn't work

case 2:
current input: 18 
enter *a *then tab* //*doesn't work

我检查了敲除代码,看看在运行以下代码时会发生什么情况:-

if(isNaN(value))
   self.age(18);

..在以下行中:-

// Ignore writes if the value hasn't changed
if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) { 

_latestValue和都arguments[0]具有相同的值(18),所以它什么也不做。由于年龄值没有变化,现在 viewmodel 属性和 UI 不同步。

这是因为我做错了吗?

4

3 回答 3

2

我有同样的情况,当我使用淘汰赛 3.0 时。但是这些技巧对我没有帮助,因为现在淘汰赛仅在计算属性值更改时才通知

我解决了问题:1)只使用通知:总是

function ageViewModel(data) {
    //notify will should be always, because age is a primitive type  
    this.age = ko.observable(data.age).extend({notify: "always"});
    this.GetAge = ko.computed({
        read: function () {
            // notify will  should be always, because computed return values of a primitive type.
            return this.age();
        },
        write: function (value) {
            value = parseInt(String(value).replace(/[^\d]/g, ""));
            if (isNaN(value)) {
                this.age(18);
            }
            else this.age(value);

        },
        owner: this
    }).extend({notify: "always"});

};

2) 使用 notify:always 和 knockout.mapping

function ageViewModel(data) {
    ko.mapping.fromJS(data, {}, this);
    //notify will should be always, because age is a primitive type  
    this.age = this.age.extend({notify: "always"});
    this.GetAge = ko.computed({
        read: function () {
            // notify will  should be always, because computed return values of a primitive type.
            return this.age();
        },
        write: function (value) {
            value = parseInt(String(value).replace(/[^\d]/g, ""));
            if (isNaN(value)) {
                this.age(18);
            }
            else this.age(value);

        },
        owner: this
    }).extend({notify: "always"});

};
于 2014-11-05T19:53:24.997 回答
2

问题是,如果您为 observable 输入相同的值,它不会认为这是值的变化,也不会通知订阅者。如果你连续多次进入错误状态,18会是第一次设置的年龄并再次设置,不会发生更改事件。

话虽如此,要解决此问题,您必须手动通知订阅者。你可以简单地通过调用valueHasMutated()observable 来做到这一点。

self.GetAge = ko.computed({
    read: function () {
        return self.age();
    },
    write: function (value) {
        value = parseInt(String(value).replace(/[^\d]/g, ""));
        if (isNaN(value)) self.age(18);
        else self.age(value);
        self.age.valueHasMutated(); // notify subscribers
    }
});
于 2013-03-26T22:08:02.697 回答
0

解决此问题的一种简单方法是将年龄设置为 0,然后返回默认值。

即,更改为:

if(isNaN(value)) {
    self.age(0);
    self.age(18);
}

我不知道淘汰赛会认为是“正确”的方式,但这可能就是我会做的。

于 2013-03-26T21:34:38.147 回答