javascript - data - knockout js for
Knockout Filtering en Matriz Observable (3)
Es posible que desee echar un vistazo al plugin Proyecciones Knockout del autor del knockout original. Tiene ventajas de rendimiento en escenarios con grandes colecciones . Ver blogpost para más detalles.
self.filterProducts = self.products.filter(function(prod) {
return !self.currentFilter() || prod.genre == self.currentFilter();
});
Empecé a aprender Knockout y estoy teniendo problemas para filtrar una matriz observable al hacer clic en un botón y mostrar los resultados.
Este es mi modelo:
function Product(data) {
this.id = data.id;
this.name = data.name;
this.price = data.price;
this.description = data.desc;
this.image = data.image;
this.genre = data.genre;
this.show = data.show;
this.offer_desc = data.offer_desc;
this.offer_id = data.offer_id;
}
function ProductModel() {
var self = this;
self.products = ko.observableArray([]);
$.getJSON(''../PHP/Utilities.php?json=true'', function(json) {
var mappedProducts = $.map(json, function(item) { return new Product(item) });
self.products(mappedProducts);
});
self.filterProducts = ko.computed(function(genre) {
if(typeof genre === ''undefined'') {
return self.products(); //initial load when no genre filter is specified
} else {
return ko.utils.arrayFilter(self.products(), function(prod) {
return prod.genre = genre;
});
}
});
}
ko.applyBindings(new ProductModel());
Este es el html:
<div data-bind="foreach: filterProducts">
<div class="row">
<div class="col-md-2">
<img data-bind="attr:{src: ''../images/'' + image, alt: name}" />
</div>
<div class="col-md-2" data-bind="text: name"></div>
<div class="col-md-1" data-bind="text: price"></div>
<div class="col-md-3" data-bind="text: description"></div>
<div class="col-md-1" data-bind=''text: offer_id''>
<div class="col-md-2" data-bind="text: genre"></div>
<div class="col-md-1" data-bind="text: show"></div>
</div>
</div>
Tampoco estoy seguro de cómo enlazar una función de clic para filtrar los productos en el género. Pensé algo como esto ... pero no funciona
<button data-bind="click: filter(''1'')"> Filter </button>
self.filter = function(genre) {
self.filterProducts(genre);
}
No puede tener una función con parámetros dentro de ko.computed
.
Lo que necesita es almacenar el filtro actual en una nueva propiedad y usarlo en su computador
function ProductModel() {
var self = this;
self.products = ko.observableArray([]);
self.currentFilter = ko.observable(); // property to store the filter
//...
self.filterProducts = ko.computed(function() {
if(!self.currentFilter()) {
return self.products();
} else {
return ko.utils.arrayFilter(self.products(), function(prod) {
return prod.genre == self.currentFilter();
});
}
});
}
Y en su controlador de click
simplemente configure el filtro actual:
<button data-bind="click: function() { filter(''1'') }"> Filter </button>
self.filter = function(genre) {
self.currentFilter(genre);
}
Demo JSFiddle
Tenga en cuenta que la function() { }
necesaria si desea pasar argumentos adicionales a en el enlace de click
(ver también en la documentation ), de lo contrario Knockout ejecutaría su función cuando analiza el enlace y no cuando hace clic en el botón.
Primero lo malinterpretas / usas para los computed Observables
. De la documentación de KnockoutJS :
Estas son funciones que dependen de uno o más observables, y se actualizarán automáticamente cada vez que cambie alguna de estas dependencias.
Su filterProducts
computable observable Los filterProducts
dependen de los products
matriz observables que no cambia , solo lee su valor. Por lo tanto, no hay nada que notificar a filterProducts
para que se vuelva a evaluar.
Entonces, ¿cuál sería la solución rápida y simple?
- Define un nuevo objeto observable
filterProducts
que dependerán tusfilterProducts
. - Cambie los productos de
filterProducts
para que compruebe el valor defilteredGenre
y, en función de ello, devuelva los productos filtrados. - Cambie la función de
filter
para que cuando obtenga un nuevogenre
cambiefilteredGenre
que daría como resultado una reevaluación de losfilterProducts
calculadosfilterProducts
Espero que entiendas la idea.