问题
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:
- an option to select which data-column should be considered (a dropdown containing the thead option) [my columnFilter] and then
- 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.
- define a custom a filter
- 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.
来源:https://stackoverflow.com/questions/29273567/angular-filters-how-to-pre-filter-so-angular-filters-consider-only-a-partial-of