Knockout Filtering on Observable Array

前端 未结 3 1073
天命终不由人
天命终不由人 2020-12-30 18:51

I\'ve started learning Knockout and I\'m having some trouble filtering an observable array on a button click and displaying the results.

This is my model:

         


        
相关标签:
3条回答
  • 2020-12-30 19:03

    First you mis-understand/use for computed Observables. From KnockoutJS documentation:

    these are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change.

    Your computed observable filterProducts depend on observable array products which you does not change, you just read it's value. So, there is nothing to notify filterProducts to be re-evaluated.

    So, what would be quick simple fix?

    1. Define a new observable object filteredGenre on which your filterProducts will depend on.
    2. Change filterProducts so that it check for the value of filteredGenre and based on, it return filtered products.
    3. Change filter function so that when it get new genre it changes filteredGenre which would result in re-evaluating of computed filterProducts

    I hope you got the idea.

    0 讨论(0)
  • 2020-12-30 19:25

    You might want to have a look at Knockout Projections plugin from the author of original knockout. It has performance advantages in scenarios with large collections. See blogpost for more details.

    self.filterProducts = self.products.filter(function(prod) {
        return !self.currentFilter() || prod.genre == self.currentFilter();
    });
    
    0 讨论(0)
  • 2020-12-30 19:26

    You cannot have a function with parameters inside a ko.computed.

    What you need is store the current filter in a new property and use that in your computed

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

    And in your click handler just set the current filter:

    <button data-bind="click: function() { filter('1') }"> Filter </button>
    
    self.filter = function(genre) {
        self.currentFilter(genre);
    }
    

    Demo JSFiddle

    Note the function() { } in needed if you want to pass additional arguments a in click binding (see also in the documentation), otherwise Knockout would execute your function when it parses the binding and not when you click on the button.

    0 讨论(0)
提交回复
热议问题