Backbone.js - 根据包含多个关键字的Array过滤集合

时间:2013-01-14 16:20:10

标签: javascript backbone.js underscore.js

我正在使用Backbone.js/Underscore.js呈现HTML表,当您在文本框中键入时,该表会进行过滤。在这种情况下,它是一个基本的电话簿 该表的内容来自一个由JSON文件填充的Collection。 下面是JSON文件的基本示例:

[{
    "Name":"Sales and Services",
    "Department":"Small Business",
    "Extension":"45446",
},
{
    "Name":"Technical Support",
    "Department":"Small Business",
    "Extension":"18800",
},
{
    "Name":"Research and Development",
    "Department":"Mid Market",
    "Extension":"75752",
}]

我将文本框值转换为小写,然后将其值与Collection一起传递给此函数,然后将返回的值分配给新的Collection并使用它重新呈现页面。

filterTable = function(collection, filterValue) {
    var filteredCollection;
    if (filterValue === "") {
        return collection.toJSON();
    }
    return filteredCollection = collection.filter(function(data) {
        return _.some(_.values(data.toJSON()), function(value) {
            value = (!isNaN(value) ? value.toString() : value.toLowerCase());
            return value.indexOf(filterValue) >= 0;
        });
    });
};

问题在于函数是文字的。要从我的示例中找到“销售和服务”部门,我必须准确输入,或者只是“销售”或“服务”。我无法输入“sal serv”,仍然能找到我想要的东西。

我已经编写了一些javascript,将文本划分为一个Word数组(现在更新为使用中的代码)似乎非常可靠。

toWords = function(text) {
    text = text.toLowerCase();
    text = text.replace(/[^A-Za-z_0-9@.]/g, ' ');
    text = text.replace(/[\s]+/g, ' ').replace(/\s\s*$/, '');
    text = text.split(new RegExp("\\s+"));
    var newsplit = [];
    for (var index in text) {
        if (text[index]) {
            newsplit.push(text[index]);
        };
    };
    text = newsplit;
    return text;
};

我想循环遍历“split”数组中的每个单词,并检查每个单词是否存在于其中一个键/值中。只要存在所有单词,它就会传递真值迭代器并添加到Collection中并在表中呈现。

所以在我的例子中,如果我输入“sal serv”,它会发现这两个字符串都存在于第一个项目的Name中,并且会返回。
但是,如果我输入“销售业务”,则不会返回,因为虽然两个值都出现在该项目中,但“名称”部分中不存在相同的两个单词。

我只是不确定如何在Backbone / Underscore中写这个,或者即使这是最好的方法。我查看了文档并且不确定哪个函数最简单。

我希望这是有道理的。我对Javascript有点新意,我意识到自己已经潜入了深渊,但学习是有趣的部分;-)
如果需要,我可以提供更多代码或JSFiddle。

1 个答案:

答案 0 :(得分:1)

使用下划线的anyall可以让您相对轻松。这是它的要点:

  var toWords = function(text) {
    //Do any fancy cleanup and split to words
    //I'm just doing a simple split by spaces.
    return text.toLowerCase().split(/\s+/);
  };

  var partialMatch = function(original, fragment) {   
    //get the words of each input string
    var origWords = toWords(original + ""), //force to string
        fragWords = toWords(fragment);

    //if all words in the fragment match any of the original words, 
    //returns true, otherwise false
    return _.all(fragWords, function(frag) {
      return _.any(origWords, function(orig) {
        return orig && orig.indexOf(frag) >= 0;
      });
    });
  };

  //here's your original filterTable function slightly simplified
  var filterTable = function(collection, filterValue) {
      if (filterValue === "") {
          return collection.toJSON();
      }
      return collection.filter(function(data) {
          return _.some(_.values(data.toJSON()), function(value) {
              return partialMatch(value, filterValue);
          });
      });
  };

注意:此方法计算效率非常低,因为它首先循环遍历集合中的所有项目,然后是每个项目的所有字段,然后是该项目值中的所有单词。此外,在循环内部声明了一些嵌套函数,因此内存占用不是最佳的。如果您有一小组数据,那应该没问题,但如果需要,可以进行一些优化。如果我有时间的话,我可能会稍后再回来编辑一下。

/未经测试的代码示例