2012-03-12 82 views
7

有沒有辦法創建一個ko.computed字段,通知數組元素的變化?ko.computed跟蹤數組元素的變化

我首先想到的是使用observableArray,但它沒有工作,因爲

An observableArray tracks which objects are in the array, not the state of those objects

不過,我張貼這一段代碼來說明什麼,我想做。

HTML:

<div data-bind="foreach:arr"> 
    <input type="text" value="" data-bind="value: a" /> 
</div> 

<div data-bind="foreach:arr"> 
    <p> 
     Field "a" is changed: <span data-bind="text: aChanged()? 'true': 'false'"></span> 
    </p> 
</div> 
<p> 
    Some "a" field from the array is changed: <span data-bind="text: someAChanged()? 'true': 'false'"></span> 
</p> 

的JavaScript:

function AppViewModel() { 
    this.arr = ko.observableArray([new A(), new A()]); 
    this.someAChanged = ko.computed(function() { 
     var ch = false; 
     var arr = this.arr(); 
     for (var i = 0; i < arr.length; i ++) { 
      if (arr[i].aChanged()) { 
       ch = true; 
       break; 
      } 
      return ch; 
     } 
    }, this);  
} 

function A() { 
    this.a = ko.observable(1); 
    this.aChanged = ko.computed(function() { 
     return this.a() != 1; 
    }, this); 
} 

ko.applyBindings(new AppViewModel()); 

因爲我沒有權利回答我的問題,我在這裏發佈我的想法。 我決定使用「訂閱」功能。我的解決方案是添加一個「父」鏈接到數組的元素。每當觀察的領域得到改變依賴於它的孩子家長領域得到改變過:

function Child() { 
    this._parent = null; 
    this.observableField = ko.observable(""); 
    this.observableField.subscribe(function (newVal) { 
     if (newVal... && this._parent) { 
      this._parent.anotherObservableField(...); 
     } 
    }); 
} 
Child.prototype._setParent(parent) {...} 

回答

2

你需要確保計算的someAChanged正在註冊您的陣列中的每個項目的依賴。

像這樣的東西應該工作:

function AppViewModel() { 
    this.arr = ko.observableArray([new A(), new A()]); 
    this.someAChanged = ko.computed(function() { 
     var ch = false; 
     var changedItem = null; 
     var arr = this.arr(); 

     ko.utils.arrayForEach(this.arr(), function(item){ 
      var changed = item.changed(); //someAChanged registers a change subscription here 

      if(changed && !ch){ 
       ch = true; 
       changedItem = item; 
      } 
     }); 

     return changedItem; 
    }, this);  
}; 

本質上講,這注冊一個「變」認購陣列中的每個項目。您之前的代碼在找到的第一個代碼處停止,這意味着陣列中沒有任何其他項目添加了「更改」訂閱。如果您的陣列中有很多項目,則循環訪問陣列中的每個項目,並使其成爲您的someAChanged計算得出的的依賴項,則可能會很昂貴。

上面的代碼還會返回更改的第一項。我認爲這是你想要的。如果不是,那麼重新工作以返回一系列已更改的項目會非常容易。

+0

[那伏乃爾古普塔(http://stackoverflow.com/users/3846772/navneet-gupta)登載:「如何,如果新項目加入到observableArray它的工作他們如何訂閱? ?」 – 2015-06-18 06:32:12

+0

@PeterO不應該是一個問題,因爲計算調用this.arr(),所以它也註冊到數組中,然後在'ko.utils.arrayForEach'調用中,將訂閱'changed'道具的新增項目。 – Tyblitz 2015-06-18 08:08:24

0

我做這件事是創建並檢查是否有任何我想結帳如果該字段的設置一個簡單的初始值在計算觀察到的改變這樣的:

var initPrice = line.Price; 
    var initCurrency = line.IdCurrency; 

    self.isModified = ko.computed(function() { 
     return self.Price() !== initPrice || self.IdCurrency() !== initCurrency; 
    }); 
0

你幾乎有我的想法。你的html和你的淘汰賽一樣好,但你的一些改變計算函數不能正常工作。如果A發生了變化,您將ch變量設置爲true並跳出for循環,但您從未真正返回true。實際上,你根本不需要ch變量。

function AppViewModel() { 
    this.arr = ko.observableArray([new A(), new A()]); 
    this.someAChanged = ko.computed(function() { 
     var arr = this.arr(); 
     for (var i = 0; i < arr.length; i ++) { 
      if (arr[i]().aChanged()) { 
       return true; 
      } 
     } 
     return false; 
    }, this); 
}