2012-03-12 13 views
7

¿Hay alguna manera de crear un campo ko.computed notificado de los cambios que se producen en los elementos de una matriz?cambios de seguimiento ko.computed de los elementos de una matriz

Lo primero que pensé fue utilizar observableArray, pero no funcionó, porque

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

Aún así, les dejo este pedazo de código para ilustrar lo que estoy tratando de hacer.

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

Como no tengo ningún derecho a responder a mis propias preguntas, les dejo mi idea aquí. Decidí usar la función "suscribir". Mi solución es agregar un enlace "principal" a los elementos de una matriz. Siempre que un campo observable se cambia un campo de matriz dependiente de sus hijos se cambia demasiado:

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) {...} 

Respuesta

2

Tendrá que asegurarse de que el someAChanged computarizada está registrando una dependencia en cada elemento de la matriz.

Algo como esto debería funcionar:

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

En esencia, este registra una suscripción de "cambio" para cada elemento de la matriz. Tu código anterior se detenía en el primero que encontró, lo que significa que ninguno de los otros elementos en tu matriz tenía suscripciones de "cambio" añadidas. Pasar por cada elemento del conjunto y convertirlo en una dependencia de someAChanged calculado podría ser costoso si tiene muchos elementos en el conjunto.

El código anterior también devolverá el primer elemento que cambió. Supuse que esto era lo que querías. De lo contrario, sería muy fácil volver a trabajar para devolver una serie de elementos modificados.

+0

[Navneet Gupta] (http://stackoverflow.com/users/3846772/navneet-gupta) ha publicado esto: "¿Cómo funciona si se agregan nuevos elementos en el observableArray ¿Cómo están suscritos a? ? " –

+0

@PeterO no debería ser un problema, ya que el cálculo invoca 'this.arr()', por lo que también se registra en la matriz, luego en la llamada 'ko.utils.arrayForEach', se suscribirá a' changed' prop del artículo recién agregado. – Tyblitz

0

lo hice el establecimiento de un simple valores iniciales de crear y comprobar si hay alguna del campo i desea para la obtención Si se cambian en un observables calculada así:

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

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

Usted eran casi allí creo. Su html está bien, así como su knockout, pero su función calculada de algún modo no funcionaba correctamente. Si un A había cambiado, establecías la variable ch en true y rompiendo el ciclo for, pero nunca regresaste verdadero. En realidad, no necesita la variable ch en absoluto.

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