2012-03-12 119 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); 
}