按嵌套数组的属性过滤 - Knockout

时间:2016-07-01 13:37:44

标签: javascript json knockout.js

我在使用Knockout out过滤嵌套数组时遇到了一些问题。

我希望能够通过' tag-names'来过滤数组。以及' name'。

即。输入' whal'并且所有包含具有该名称的标记的对象都将在网格中过滤。

小提琴:https://jsfiddle.net/king_s/fj9L3wjz/3/

<input data-bind="value: searchQuery, valueUpdate: 'afterkeydown'" />

<div data-bind="foreach: filter" class="grid">
    <p data-bind="text: name"></p>
</div>
(function(){
    var ViewModel = function() {
        var self = this;
        var obj = { "id": 11, 
            "name": "mouse", 
            "tags": [{ "id": 1, 
                "name": "critter"
            }] 
        };
        var obj2 = { "id": 12, 
            "name": "dolphin", 
            "tags": [{ "id": 2,
                "name": "fish"
            }, 
            {"id": 3,
                "name": "whale"
            }] 
        };
        self.searchQuery = ko.observable("");
        self.array = ko.observableArray([obj, obj2]);
        self.filter = ko.computed(function() {
            if(!self.searchQuery()) {
                return self.array();
            } else {
                return ko.utils.arrayFilter(self.array(), function(obj) {
                    return obj.name.toLowerCase().indexOf(self.searchQuery().toLowerCase()) > -1;
                });
            }
        });
    };
    ko.applyBindings(new ViewModel());
})();

3 个答案:

答案 0 :(得分:2)

只需为标签添加第二次检查:

return ko.utils.arrayFilter(self.array(), function(obj) {
            var tagsCheck = ko.utils.arrayFilter(obj.tags, function(tag) {
            return tag['name'].toLowerCase().indexOf(self.searchQuery().toLowerCase()) > -1});

                return (obj.name.toLowerCase().indexOf(self.searchQuery().toLowerCase()) > -1) || tagsCheck.length;
                });

还要检查此fiddle

答案 1 :(得分:1)

你必须像这样迭代你的子对象:

self.filter = ko.computed(function() {
  if (!self.searchQuery()) {
    return self.array();
  } else {
    return ko.utils.arrayFilter(self.array(), function(obj) {
      var value = obj.name.toLowerCase().indexOf(self.searchQuery().toLowerCase());
      var compensation = 0; // Compensate for how many tags there are
      obj.tags.forEach(function (tag) {
        compensation--;
        value += tag.name.toLowerCase().indexOf(self.searchQuery().toLowerCase());
      })
      // Final value is greater than -1 + (-1 * number of tags)
      return value > -1 + compensation;
    });
  }
});

在这里试试fiddle

修改

我受到启发,更新了我对以下内容的回答,因此看起来更清晰:

self.filter = ko.computed(function() {
  if (!self.searchQuery()) {
    return self.array();
  } else {
    return ko.utils.arrayFilter(self.array(), function(obj) {
      var found = obj.name.toLowerCase().indexOf(self.searchQuery().toLowerCase()) > -1;
      obj.tags.forEach(function(tag) {
        if (tag.name.toLowerCase().indexOf(self.searchQuery().toLowerCase()) > -1) {
          found = true;
        }
      });
      return found;
    });
  }
});

在这里试试fiddle

答案 2 :(得分:0)

我前一段时间制作了KO filters extender,这有助于完成这些工作。它在observableArray上创建一个filtered属性,并允许灵活累积过滤器。

在您的HTML中,您可以:

<div data-bind="foreach: array.filtered" class="grid">

你的JS将是:

self.array = ko.observableArray([obj, obj2]).extend({filters: {
  search: function(obj) {
    var query     = self.searchQuery().toLowerCase(),
        nameMatch = obj.name.toLowerCase().match(query),
        tagMatch  = false;
    obj.tags.forEach(function(tag, i) {
      if (tag.name.toLowerCase().match(query))
        tagMatch = true;
    });
    return nameMatch || tagMatch;
  }
}});    

self.array.toggleFilter('search', true);

请参阅updated fiddle