在这种情况下,Knockoutjs不会更新UI

时间:2013-03-26 21:29:48

标签: knockout.js

我对KO相对较新(2天前开始),并尝试了一些简单的例子。目前,我遇到了这段代码的问题。

<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并在解析之后是否我正在尝试将年龄设置为其默认值 即18.我在html上有一个简单的逻辑,如果年龄低于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])) { 

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

这是因为我做错了吗?

3 个答案:

答案 0 :(得分:2)

问题在于,如果为observable输入相同的值,则不会将其视为值的更改,也不会通知订阅者。如果您连续多次输入错误状态,18将首先设置为年龄并再次设置,不会发生任何更改事件。

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

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

答案 1 :(得分: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"});

};

答案 2 :(得分:0)

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

即,改为:

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

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