Ich habe angefangen, Knockout zu lernen und habe Probleme beim Filtern eines beobachtbaren Arrays mit einem Klick auf eine Schaltfläche und beim Anzeigen der Ergebnisse.
Das ist mein Modell:
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());
Dies ist das 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>
Ich bin mir auch nicht sicher, wie ich eine Klickfunktion binden soll, um die Produkte nach Genre zu filtern. Ich dachte so etwas ... aber es funktioniert nicht
<button data-bind="click: filter('1')"> Filter </button>
self.filter = function(genre) {
self.filterProducts(genre);
}
Sie können keine Funktion mit Parametern innerhalb eines ko.computed
Haben.
Was Sie brauchen, ist, den aktuellen Filter in einer neuen Eigenschaft zu speichern und diesen in Ihrem berechneten zu verwenden
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();
});
}
});
}
Und in Ihrem click
-Handler setzen Sie einfach den aktuellen Filter:
<button data-bind="click: function() { filter('1') }"> Filter </button>
self.filter = function(genre) {
self.currentFilter(genre);
}
Demo JSFiddle
Beachten Sie das function() { }
in, wenn Sie zusätzliche Argumente in click
-Bindung übergeben möchten (siehe auch in der Dokumentation ), andernfalls würde Knockout Ihre Funktion ausführen, wenn es analysiert die Bindung und nicht, wenn Sie auf die Schaltfläche klicken.
Zuerst missverstehst du/verwendest du für computed Observables
. Von KnockoutJS-Dokumentation :
hierbei handelt es sich um Funktionen, die von einer oder mehreren anderen Observablen abhängig sind und automatisch aktualisiert werden, wenn sich eine dieser Abhängigkeiten ändert.
Ihre berechnete beobachtbare filterProducts
hängt von dem beobachtbaren Array products
ab, das Sie nicht ändern . Sie lesen nur den Wert . Es gibt also nichts zu benachrichtigen, dass die filterProducts
erneut ausgewertet werden soll.
Was wäre also eine schnelle, einfache Lösung?
filteredGenre
, von dem Ihre filterProducts
abhängt.filterProducts
so, dass es den Wert von filteredGenre
prüft und basierend darauf gefilterte Produkte zurückgibt.filter
so, dass sie beim Abrufen einer neuen genre
die Funktion filteredGenre
ändert, was zu einer Neubewertung der berechneten filterProducts
führen würde.Ich hoffe du hast die Idee.
Vielleicht möchten Sie sich das Knockout-Projektionen -Plugin des Autors des ursprünglichen Knockouts ansehen. In Szenarien mit großen Sammlungen hat es Leistungsvorteile. Siehe Blogpost für weitere Details.
self.filterProducts = self.products.filter(function(prod) {
return !self.currentFilter() || prod.genre == self.currentFilter();
});