2013-03-26 66 views
4

我對KO(開始2天后)比較陌生,正在嘗試一些簡單的示例。目前,我對這段代碼有問題。Knockoutjs在這種情況下不更新UI

<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,我正在改變跨度的背景紅色如果年齡低於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不同步。

這是因爲我做錯了嗎?

+0

你應該考慮使用[淘汰賽驗證] (https://開頭github上。com/ericmbarnard/Knockout-Validation)插件。 – 2013-03-26 21:51:08

回答

1

問題是,如果您爲可觀察項輸入相同的值,則不會將其視爲值的更改,也不會通知訂閱者。如果連續多次輸入錯誤狀態,則18將首先設置爲設定時間,然後再次設置,不會發生更改事件。

這樣說,要解決這個問題,你必須手動通知訂閱者。你可以簡單地通過在可觀察對象上調用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 
    } 
}); 
+0

是的..這就是我一直在尋找的東西。非常感謝。 :) 順便說一句我在knockoutjs.com(手冊,文檔,例子等)沒有看到這個提到的任何地方,但現在注意到它在knockoutjs代碼中。 正在學習代碼只知道/學習的方法嗎? – miztaken 2013-03-26 22:19:33

+0

在這種情況下,是的。不幸的是,還有一些功能沒有正式記錄。雖然我不會說你必須真正研究它,但是如果你遇到了一些看起來不正確的事情,就像你已經在這裏做的那樣,那麼就看看實現。 – 2013-03-26 22:35:21

0

解決此問題的一種簡單方法是將年齡設置爲0,然後回到默認值。

即更改爲:

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

我不知道是什麼淘汰賽會認爲是「正確」的方式,但是這可能是我會怎麼做。

+0

是的..這是伎倆..但在這裏,我們將調用同樣的方法兩次只是爲了通過這個測試: - if((!!observable ['equalityComparer'])||!observable ['equalityComparer']( _latestValue,參數[0])){ 我只是想知道是否有比這更好的解決方案。 – miztaken 2013-03-26 21:45:16

2

我有同樣的情況,當我使用淘汰賽3.0。但這些triks不幫我,因爲現在淘汰賽通知只有當計算屬性值變化

而且我解決問題: 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)使用通知:總是和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"}); 

};