2012-07-02 8 views
37

Me gustaría saber cómo crear una matriz observable calculada.Cómo crear una matriz observable calculada en Knockout

En mi modelo de vista, tengo 2 matrices observables, y me gustaría tener una matriz observable calculada que sea simplemente ambas matrices combinadas.

function ViewModel() { 
    var self = this; 
    self.listA= ko.observableArray([]); 
    self.listB = ko.observableArray([]); 
    self.masterList= //combine both list A and B 

Respuesta

33

Esto combinará las dos matrices y devolverá la lista combinada. Sin embargo, no es una matriz observable calculada (no sé si eso es posible), sino un observable computable regular.

self.masterList = ko.computed(function() { 
    return this.listA().concat(this.listB()); 
}, this); 
+18

creo esta respuesta es defectuosa para la mayoría de los casos de uso: el valor del observable calculado es un conjunto regular, no un conjunto observable (aproximadamente indicado en la respuesta). Por lo tanto, actualizar 'listA' o' listB' reemplazará por completo la matriz en sí en lugar de actualizar su contenido (que es lo que queremos en el 99% de los casos). ** Esto significa que no debe vincular las vistas a este observable. ** En efecto, este código es tan útil como su variante no computada. Ver otras respuestas para diferentes enfoques. – tne

+0

No funcionará en este caso, pero el plugin knockout [knockout-projections] (https://github.com/stevesanderson/knockout-projections) implementa matrices observables computadas mucho más eficientes utilizando las nuevas [suscripciones de cambio de matriz] (http://blog.stevensanderson.com/2013/10/08/knockout-3-0-release-candidate-available/). Este complemento podría ampliarse para admitir una operación de concat eficiente. – Singularity

7

Un observableArray es simplemente un observable con algunas propiedades más. Por lo tanto, un observable calculado que devuelve una matriz en el cierre se tratará como una matriz.

+3

Bueno, más o menos. Acabo de probarlo y parece que a menos que se declare como una matriz observable, los métodos como el cambio y el pop no se desglosan por ti. – Eirinn

9

Sé que esto es una vieja pregunta, pero pensé en tirar mi respuesta allí:

var u = ko.utils.unwrapObservable; 

ko.observableArray.fn.filter = function (predicate) { 
    var target = this; 

    var computed = ko.computed(function() { 
     return ko.utils.arrayFilter(target(), predicate); 
    }); 

    var observableArray = new ko.observableArray(u(computed)); 

    computed.subscribe(function (newValue) { observableArray(newValue); }); 

    return observableArray; 
}; 
10
self.masterList = ko.observableArray(); 
ko.computed(function() { 
    self.masterList(self.listA().concat(self.listB())); 
}); 

Similar a la respuesta de Joe Flateau en espíritu, pero me gusta pensar que este método es más simple .

+0

Así es como yo iba a hacerlo también, pero ¿esto no sigue siendo el problema como la respuesta aceptada? en que cualquier cambio causará que cualquier vista ligada a 'masterList' sea redibujada por completo? –

+0

@AdamLewis: Sí, esto reconstruye toda la matriz y, dependiendo del motor de visualización, puede o no volver a representar todo el subgráfico DOM para las vistas que estén vinculadas a la misma (aunque no necesariamente, podría hacer una diferencia y aplicarse eso). Tenga en cuenta que aún podría ser la mejor solución para evitar muchas actualizaciones. Este no es el problema que delineé con respecto a la respuesta que mencionas, donde si el motor de vista captura la propiedad de la matriz en sí misma (a diferencia de la ruta hacia ella) entonces nunca detectaría que cambiaste la matriz (ya que no es observable) y por lo tanto, nunca se actualizaría * en absoluto *. – tne

+0

@tne Estoy usando esta respuesta por ahora, pero parece muy lenta ... tal vez estoy haciendo algo diferente. sin embargo, ¿esta solución está rompiendo el propósito de KO?¿Hay alguna otra forma de resolver el problema de necesitar una matriz observable calculada? Me pregunto si esta es la herramienta correcta para usar en mi (o cualquier) situación. – Nate

2

No estoy seguro de si esta es la opción más eficiente, pero es bastante simple y funciona para mí. Los rendimientos ko.computed una matriz observable como a continuación:

self.computedArrayValue = ko.computed(function() { 
    var all = ko.observableArray([]); 
    .... 
    return all(); 
}); 

ejemplo de trabajo de un código: HTML:

<div data-bind="foreach: days"> 
    <button class="btn btn-default btn-lg day" data-bind="text: $data, click: $root.dayPressed"></button>   
</div> 

función Javascript sobre el modelo de vista:

self.days = ko.computed(function() { 
    var all = ko.observableArray([]); 
    var month = self.selectedMonth(); //observable 
    var year = self.selectedYear();  //observable 
    for (var i = 1; i < 29; i++) { 
     all.push(i); 
    } 
    if (month == "Feb" && year % 4 == 0) { 
     all.push(29); 
    } else if (["Jan","Mar","May","Jul","Aug","Oct","Dec"].find((p) => p == month)) { 
     [29,30,31].forEach((i) => all.push(i)); 
    } else if (month != "Feb") { 
     [29,30].forEach((i) => all.push(i));     
    } 
    return all(); 
}); 
Cuestiones relacionadas