Knockout - Filtering Objects in Observable Arrays by multiple Object Properties

半世苍凉 提交于 2019-12-12 05:28:35

问题


So here it is... I am attempting to build a data-grid with Knockout.js. I want to build it from scratch (skill building exercise), so I don't want to use KoGrid or SimpleGrid.

The issue I am having is that I want to be able to filter the results based on a text input. This filter has to go through each object and filter on ONLY the keys that match a column's value property.

Example

Filtering with the value '1' will return both of data's objects with properties that contain 1. (ID 1 and ID 3).

JSFIDDLE

HTML

<div data-bind="foreach: filteredItems">
    <p data-bind="text: LastName"></p>
</div>
<p>Filter:
    <input data-bind="value: filter, valueUpdate: 'keyup'" />
</p>
<p>Filter Value: <span data-bind="text: filter"></span></p>

JavaScript

var data = [{
    Id: 1,
    LastName: "Franklin"
}, {
    Id: 2,
    LastName: "Green"
}, {
    Id: 3,
    LastName: "1"
}];

var columns = [{
    value: 'Id'
}, {
    value: 'LastName'
}];

var Filtering = function (data, columns) {
    var self = this;

    self.items = ko.observableArray(data);
    self.columns = ko.observableArray(columns);
    self.filter = ko.observable();

    self.filteredItems = ko.computed(function () {
        var filter = self.filter();
        console.log(filter);
        if (!filter) {
            return self.items();
        } else {
            return ko.utils.arrayFilter(self.items(), function (item) {
                console.log('Filtering on Item');
                ko.utils.arrayForEach(self.columns(), function (c) {
                    var val = item[c.value];
                    if (typeof val === 'number') {
                        val = val.toString();
                    }
                    console.log('Filtering on Column');
                    return val.toLowerCase().indexOf(filter.toLowerCase()) > -1;
                });
            });
        }

    });
};

ko.applyBindings(new Filtering(data, columns));

It works great statically setting the c.value in item[c.value], but when I try to loop through the array of self.columns() I do not get results returned.

Recs

I have jQuery, Knockout.js 3.0, and underscore.js at my disposal.

Any help is greatly appreciated.


回答1:


Just few problems in your code :

  • a Boolean needs to be returned as output of ko.utils.arrayFilter
  • you need a sort of sum up for arrayForEach as your filter is an OR

I changed your code to address those details :

var Filtering = function (data, columns) {
    var self = this;

    self.items = ko.observableArray(data);
    self.columns = ko.observableArray(columns);
    self.filter = ko.observable();

    self.filteredItems = ko.computed(function () {
        var filter = self.filter();
        console.log(filter);
        if (!filter) {
            return self.items();
        } else {
            return ko.utils.arrayFilter(self.items(), function (item) {
                console.log('Filtering on Item');
                var matching = -1;
                ko.utils.arrayForEach(self.columns(), function (c) {
                    var val = item[c.value];
                    if (typeof val === 'number') {
                        val = val.toString();
                    }
                    console.log('Filtering on Column');
                    matching+= val.toLowerCase().indexOf(filter.toLowerCase())+1;
                });
                 console.log(matching);
                return matching>=0;
            });
        }

    });
};

Worked for me there : http://jsfiddle.net/Lzud7fjr/1/




回答2:


Your filtering case isn't returning anything. ko.utils.arrayFilter() should return a truthy value if the item should be included in the result. However since it doesn't return anything, nothing is included in the result. You'll need to rewrite it so it will return something.

I suppose you could change the inner ko.utils.arrayForEach() call to a filter and return true if the result is non-empty.

self.filteredItems = ko.computed(function () {
    var filter = self.filter();
    console.log(filter);
    if (!filter) {
        return self.items();
    } else {
        return ko.utils.arrayFilter(self.items(), function (item) {
            console.log('Filtering on Item');
            var result = ko.utils.arrayFilter(self.columns(), function (c) {
                var val = item[c.value];
                if (typeof val === 'number') {
                    val = val.toString();
                }
                console.log('Filtering on Column');
                return val.toLowerCase().indexOf(filter.toLowerCase()) > -1;
            });
            return !!result.length;
        });
    }
});


来源:https://stackoverflow.com/questions/26374056/knockout-filtering-objects-in-observable-arrays-by-multiple-object-properties

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!