Angular 过滤器:如何进行预过滤,使得 Angular 过滤器仅考虑整个数据对象的部分内容。

3

我有一个大型数据表格(通过json api获取数据),具有多个列,并希望实现多个过滤器,完成以下操作:

  1. 选择要考虑的数据列的选项(包含 thead 选项的下拉列表)[我的 columnFilter]
  2. 用于过滤特定数据部分的输入字段 [我的 searchFilter]

我已经让 searchFilter 正常工作了,但我不确定如何连接 columnFilter 并使 searchFilter 仅适用于所选的数据部分。

假设我只想查看包含单词“blue”的描述。

如何绑定这两个过滤器并使其正常工作?

以下是我的一些代码:

  Select data column:
  <select ng-model="columnFilter" ng-options="heading for heading in headings">
  </select>
</div>
<div class="col-sm-12">
   Filter selection: <input type='text' ng-model="searchFilter" />
</div>
<table class="table table-bordered">
    <thead>
      <tr>
        <th>URL</th>
        <th>Title</th>
        <th>Traffic</th>
        <th>Description</th>
        <th>ID</th>
      </tr>
  </thead>
  <tbody ng-repeat="url in urls | filter:searchFilter">
    <tr>
      <td>{{url.url}}</td>
      <td>{{url.title}}</td>
      <td>{{url.traffic}}</td>
      <td>{{url.descr}}</td>
      <td>{{url.id}}</td>
    </tr>
    </tbody>
</table>

同时提供一个可用的Plunker链接:http://plnkr.co/edit/TddllGiey0RmCx18eVdd?p=preview

3个回答

1
据我所知,对于Angular而言,解决此问题有两种主要方式:
  1. 定义自定义过滤器
  2. 定义一个函数以过滤您的数据,并使用ng-show或ng-hide调用它

我有一个大型数据表

如果我理解正确,你之所以特别提到这一点是因为性能是一个重要问题。

有一篇很好的文章介绍了这两种解决方案之间的区别:http://www.bennadel.com/blog/2487-filter-vs-nghide-with-ngrepeat-in-angularjs.htm

由于性能可能对您非常重要,我建议您选择第二种方法。

在您的视图中:

<tbody ng-repeat="url in urls" ng-show="filterUrl(url)">

在你的控制器中:
$scope.searchFilter = "";
$scope.columnFilter = $scope.headings[5];

$scope.filterUrl = function(url){ 
  if(!$scope.searchFilter || $scope.searchFilter == "")
    return url;
  var searchFilter= $scope.searchFilter.toLowerCase();
  var trafficString = url.traffic.toString();
  var idString = url.traffic.toString();
  switch($scope.columnFilter){
    case $scope.headings[0]:
      return url.title.toLowerCase().indexOf(searchFilter) != -1;
    case $scope.headings[1]:
      return url.url.toLowerCase().indexOf(searchFilter) != -1;
    case $scope.headings[2]:
      return trafficString.indexOf(searchFilter) != -1;
    case $scope.headings[3]:
      return url.descr.toLowerCase().indexOf(searchFilter) != -1;
    case $scope.headings[4]:
      return idString.indexOf(searchFilter) != -1;
    case $scope.headings[5]: 
      return url.title.toLowerCase().indexOf(searchFilter) != -1 ||
      url.url.toLowerCase().indexOf(searchFilter) != -1 ||
      trafficString.indexOf(searchFilter) != -1 ||
      url.descr.toLowerCase().indexOf(searchFilter) != -1 ||
      idString.indexOf(searchFilter) != -1;
  }
};

更新: 如果你选择第一种方法:
在你的视图中:
 <tbody ng-repeat="url in urls | filterByColumn: searchFilter :columnFilter">

过滤器:

app.filter('filterByColumn', function(){
  return function(urls, text, columnFilter){
    var processed = [];
     if(!text || text == "")
        return urls;
    urls.forEach(function(url){
      var searchFilter= text.toLowerCase();
      var trafficString = url.traffic.toString();
      var idString = url.traffic.toString();
      switch(columnFilter){
        case "Title":
          if( url.title.toLowerCase().indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Url":
          if(url.url.toLowerCase().indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Traffic":
          if(trafficString.indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Description":
          if(url.descr.toLowerCase().indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Id":
          if( idString.indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "All": 
          if( url.title.toLowerCase().indexOf(searchFilter) != -1 ||
          url.url.toLowerCase().indexOf(searchFilter) != -1 ||
          trafficString.indexOf(searchFilter) != -1 ||
          url.descr.toLowerCase().indexOf(searchFilter) != -1 ||
          idString.indexOf(searchFilter) != -1)
            processed.push(url);
          break;
      }
    });
    return processed;
  };
});

这里有一个 Plunkr:http://plnkr.co/edit/xCwI2AURFpvb6xHgYHxS?p=preview


太棒了,它正好按照我想要的方式运行,而且这篇文章也很有帮助。不过还有一个问题——将这两个过滤器合并只是我最终想要构建的4个过滤器中的第一步(类似于Google Analytics使用的此处http://awesomescreenshot.com/06b4q53x83 过滤器1:包括/排除 过滤器2:选择列(如此处解决) 过滤器3:不同的过滤选项(包括、以...开头、等于等) 过滤器4:输入字段(如此处解决)。鉴于此,您仍然建议定义函数还是更好地使用自定义过滤器? - Lilalaune
你能给我一个大概的行数吗? 100?500?1000?还是更多? - Aliz
你会在其他页面上重复使用这些筛选器吗?(分离或组合) 如果是肯定的,那么我建议您使用筛选器。 - Aliz
请检查Plunk链接,我更新了代码以使用过滤器,并添加了第二个以让您看到如何将不同的过滤器管道连接起来。(仅在Plunkr上可见) - Aliz
1
非常感谢您的帮助,真希望我能再次点赞。我检查了Plunker,但最新版本(25)似乎无法正常工作(数据表几乎为空)。 - Lilalaune
显示剩余3条评论

1

请查看以下这个示例,来自Angular页面上创建自定义过滤器的示例。 https://docs.angularjs.org/guide/filter

您可以在这里看到,您可以创建一个接受两个输入的过滤器,即实际对象和参数。通过将列名作为参数传递,您可以缩小对正确行的搜索范围。


谢谢您 - 我是Angular的新手,不确定如何将他们的示例转移到我的情况。您能否指点我正确的方向? - Lilalaune

0
我建议您编写像这样简单的自定义过滤器。
.filter('myfilter', function(){
  return function(input, column, text){
    if (!input || !column || !text) return input;
    return input.filter(function(item){
      var value = item[column.toLowerCase()];
      if (!value)return false;
      return value.indexOf(text)>-1;
    });
  };
});

你可以在HTML中使用这个过滤器。

ng-repeat="url in urls | myfilter:columnFilter:searchFilter"

这是 Plunker。


谢谢你的回复 - 我尝试了你的 Plunker,但是搜索过滤器不起作用 - 你有什么想法如何解决这个问题吗? - Lilalaune
为了让示例尽可能简单,我使用Array.filter来实现过滤函数。 如果您使用不支持Array.filter的旧浏览器,则此示例无法正常工作。 我的Chrome(和Firefox)可以正常工作。当然,您需要进行一些更改以支持旧浏览器。 - yazaki
顺便说一句,这是示例的新版本,它使用underscore.js来支持旧浏览器。我的IE9运行良好。 - yazaki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接