Angular Filters: How to pre-filter so angular filters consider only a partial of the whole data object

匿名 (未验证) 提交于 2019-12-03 00:56:02

问题:

I got a large data table (which gets its data from a json api) with multiple columns and would like to implement multiple filters doing the following:

  1. an option to select which data-column should be considered (a dropdown containing the thead option) [my columnFilter] and then
  2. an input field to filter that particular data-partial [my searchFilter]

I've got the searchFilter working, but I'm not sure how to connect the columnFilter and make the searchFilter only apply to the selected data-partial.

So let's say I'd like to only see Descriptions containing the world "blue".

How can I bind these two filters and make this work?

Here is some of my code:

  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> 

and a link to a working plunker: http://plnkr.co/edit/TddllGiey0RmCx18eVdd?p=preview

回答1:

As far as i know angular, there is two main way to solve your problem.

  1. define a custom a filter
  2. define a function to filter your data and call it with ng-show or ng-hide

I got a large data table

If i understand well, you specify that because performance is a big issue.

There is a good article which exposes the differences between those two solutions : http://www.bennadel.com/blog/2487-filter-vs-nghide-with-ngrepeat-in-angularjs.htm

As performance may be really important for you, i suggest you the second approach.

In your view:

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

In your controller:

$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;   } }; 

Update: If you choose the first approach:

In your view:

 <tbody ng-repeat="url in urls | filterByColumn: searchFilter :columnFilter"> 

The filter:

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

Here is a plunkr: http://plnkr.co/edit/xCwI2AURFpvb6xHgYHxS?p=preview



回答2:

Check how this example straight from the angular page of a creating a custom filter. https://docs.angularjs.org/guide/filter

You can see here that you can create a filter that accepts 2 inputs, the actual object and a parameter. By passing the column name as parameter, you can narrow down your search for the correct rows.



回答3:

I would recommend you to write simple custom filter like this.

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

You can use this filter in html.

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

This is plunker.



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