如何在 angularJS 中过滤多个值(OR 操作)

我想使用角度的 filter,并希望过滤多个值,如果它有任何一个值,然后它应该显示。

例如,我有这样一个结构:

一个具有属性 genres的对象 movie,我想过滤 ActionComedy

我知道我可以做 filter:({genres: 'Action'} || {genres: 'Comedy'}),但是如果我想动态地过滤它该怎么做

我如何设置 variableX$scope,当我有一个类型的数组,我必须过滤?

我可以将它构造成一个字符串,然后执行 eval(),但是我不想使用 eval () ..。

279353 次浏览

我只是创建一个自定义过滤器。他们不是那么难。

angular.module('myFilters', []).
filter('bygenre', function() {
return function(movies,genres) {
var out = [];
// Filter logic here, adding matches to the out var.
return out;
}
});

模板:

<h1>Movies</h1>


<div ng-init="movies = [
{title:'Man on the Moon', genre:'action'},
{title:'Meet the Robinsons', genre:'family'},
{title:'Sphere', genre:'action'}
];" />
<input type="checkbox" ng-model="genrefilters.action" />Action
<br />
<input type="checkbox" ng-model="genrefilters.family" />Family
<br />\{\{genrefilters.action}}::\{\{genrefilters.family}}
<ul>
<li ng-repeat="movie in movies | bygenre:genrefilters">\{\{movie.title}}: \{\{movie.genre}}</li>
</ul>

编辑 这里是链接: < a href = “ https://docs.angularjs.org/guide/filter # create-custom- filter”rel = “ noReferrer”> 创建角度滤镜

更新 : 这里是一个 小提琴,有一个精确的演示我的建议。

可以使用控制器函数进行筛选。

function MoviesCtrl($scope) {


$scope.movies = [{name:'Shrek', genre:'Comedy'},
{name:'Die Hard', genre:'Action'},
{name:'The Godfather', genre:'Drama'}];


$scope.selectedGenres = ['Action','Drama'];


$scope.filterByGenres = function(movie) {
return ($scope.selectedGenres.indexOf(movie.genre) !== -1);
};


}

HTML:

<div ng-controller="MoviesCtrl">
<ul>
<li ng-repeat="movie in movies | filter:filterByGenres">
\{\{ movie.name }} \{\{ movie.genre }}
</li>
</ul>
</div>

创建一个自定义过滤器可能有点过了,你可以直接传入一个自定义比较器,如果你有这样的多重值:

$scope.selectedGenres = "Action, Drama";


$scope.containsComparator = function(expected, actual){
return actual.indexOf(expected) > -1;
};

然后在过滤器中:

filter:{name:selectedGenres}:containsComparator

下面是自定义过滤器的实现,它将使用值数组来过滤数据。如前所述,inangularJS API AngularJS 过滤器博士支持单值多键过滤器,但下面的自定义过滤器将支持与 angularJS 相同的功能,并且还支持数组值和单值键的组合。请找到下面的代码片段,

myApp.filter('filterMultiple',['$filter',function ($filter) {
return function (items, keyObj) {
var filterObj = {
data:items,
filteredData:[],
applyFilter : function(obj,key){
var fData = [];
if (this.filteredData.length == 0)
this.filteredData = this.data;
if (obj){
var fObj = {};
if (!angular.isArray(obj)){
fObj[key] = obj;
fData = fData.concat($filter('filter')(this.filteredData,fObj));
} else if (angular.isArray(obj)){
if (obj.length > 0){
for (var i=0;i<obj.length;i++){
if (angular.isDefined(obj[i])){
fObj[key] = obj[i];
fData = fData.concat($filter('filter')(this.filteredData,fObj));
}
}


}
}
if (fData.length > 0){
this.filteredData = fData;
}
}
}
};
if (keyObj){
angular.forEach(keyObj,function(obj,key){
filterObj.applyFilter(obj,key);
});
}
return filterObj.filteredData;
}
}]);

用法:

arrayOfObjectswithKeys | filterMultiple:{key1:['value1','value2','value3',...etc],key2:'value4',key3:[value5,value6,...etc]}

下面是一个小提琴实现以上 “ filterMultiple”自定义过滤器的例子。 小提琴例子:

最佳答案是:

filter:({genres: 'Action', genres: 'Comedy'}

我相信这就是你要找的:

<div>\{\{ (collection | fitler1:args) + (collection | filter2:args) }}</div>

您可以使用 棱角过滤器的 searchField 过滤器

约翰逊:

$scope.users = [
{ first_name: 'Sharon', last_name: 'Melendez' },
{ first_name: 'Edmundo', last_name: 'Hepler' },
{ first_name: 'Marsha', last_name: 'Letourneau' }
];

HTML:

<input ng-model="search" placeholder="search by full name"/>
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
\{\{ user.first_name }} \{\{ user.last_name }}
</th>
<!-- so now you can search by full name -->

如果您想要在 Array of Objects 上进行过滤,那么您可以给出

filter:({genres: 'Action', key :value }.

个别属性将由为该属性指定的特定筛选器进行筛选。

但是,如果您希望通过单个属性进行过滤,并对所有属性进行全局过滤,那么可以执行以下操作。

<tr ng-repeat="supp in $data | filter : filterObject |  filter : search">
Where "filterObject" is an object for searching an individual property and "Search" will search in every property globally.

~Atul

我写这个字符串和功能(我知道这不是问题,但我搜索它,并得到了这里) ,也许它可以扩展。

String.prototype.contains = function(str) {
return this.indexOf(str) != -1;
};


String.prototype.containsAll = function(strArray) {
for (var i = 0; i < strArray.length; i++) {
if (!this.contains(strArray[i])) {
return false;
}
}
return true;
}


app.filter('filterMultiple', function() {
return function(items, filterDict) {
return items.filter(function(item) {
for (filterKey in filterDict) {
if (filterDict[filterKey] instanceof Array) {
if (!item[filterKey].containsAll(filterDict[filterKey])) {
return false;
}
} else {
if (!item[filterKey].contains(filterDict[filterKey])) {
return false;
}
}
}
return true;
});
};
});

用法:

<li ng-repeat="x in array | filterMultiple:{key1: value1, key2:[value21, value22]}">\{\{x.name}}</li>

角度或滤波模块

$filter('orFilter')([{..}, {..} ...], {arg1, arg2, ...}, false)

这里是链接: https://github.com/webyonet/angular-or-filter

假设您有两个数组,一个用于电影,一个用于类型

只需使用过滤器作为: filter:{genres: genres.type}

在这里体裁是数组和类型有价值的体裁

我的解决办法

ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"

我花了一些时间在它和感谢@chrismarx,我看到角的默认 filterFilter允许您通过自己的比较器。下面是经过编辑的多值比较器:

  function hasCustomToString(obj) {
return angular.isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
}
var comparator = function (actual, expected) {
if (angular.isUndefined(actual)) {
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null)) {
// No substring matching against `null`; only match against `null`
return actual === expected;
}
// I edited this to check if not array
if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
// This is where magic happens
actual = angular.lowercase('' + actual);
if (angular.isArray(expected)) {
var match = false;
expected.forEach(function (e) {
e = angular.lowercase('' + e);
if (actual.indexOf(e) !== -1) {
match = true;
}
});
return match;
} else {
expected = angular.lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}
};

如果我们想为干燥设备制作一个自定义过滤器:

angular.module('myApp')
.filter('filterWithOr', function ($filter) {
var comparator = function (actual, expected) {
if (angular.isUndefined(actual)) {
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null)) {
// No substring matching against `null`; only match against `null`
return actual === expected;
}
if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
console.log('ACTUAL EXPECTED')
console.log(actual)
console.log(expected)


actual = angular.lowercase('' + actual);
if (angular.isArray(expected)) {
var match = false;
expected.forEach(function (e) {
console.log('forEach')
console.log(e)
e = angular.lowercase('' + e);
if (actual.indexOf(e) !== -1) {
match = true;
}
});
return match;
} else {
expected = angular.lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}
};
return function (array, expression) {
return $filter('filter')(array, expression, comparator);
};
});

然后我们可以在任何地方使用它:

$scope.list=[
{name:'Jack Bauer'},
{name:'Chuck Norris'},
{name:'Superman'},
{name:'Batman'},
{name:'Spiderman'},
{name:'Hulk'}
];




<ul>
<li ng-repeat="item in list | filterWithOr:{name:['Jack','Chuck']}">
\{\{item.name}}
</li>
</ul>

最后是 噗通

注意: 期望的数组应该只包含简单的对象,如 绳子号码等。

请试试这个

var m = angular.module('yourModuleName');
m.filter('advancefilter', ['$filter', function($filter){
return function(data, text){
var textArr = text.split(' ');
angular.forEach(textArr, function(test){
if(test){
data = $filter('filter')(data, test);
}
});
return data;
}
}]);

我也遇到过类似的情况。编写自定义过滤器对我很有用。希望这能有所帮助!

约翰逊:

App.filter('searchMovies', function() {
return function (items, letter) {
var resulsts = [];
var itemMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if ( itemMatch.test(item.name) || itemMatch.test(item.genre)) {
results.push(item);
}
}
return results;
};
});

HTML:

<div ng-controller="MoviesCtrl">
<ul>
<li ng-repeat="movie in movies | searchMovies:filterByGenres">
\{\{ movie.name }} \{\{ movie.genre }}
</li>
</ul>
</div>

如情况许可,您也可以使用 ngIf:

<div ng-repeat="p in [
{ name: 'Justin' },
{ name: 'Jimi' },
{ name: 'Bob' }
]" ng-if="['Jimi', 'Bob'].indexOf(e.name) > -1">
\{\{ p.name }} is cool
</div>

下面是如何为表 Jsfiddle创建过滤器和指令的示例

指令获取列表(数据)并使用过滤器创建表

<div ng-app="autoDrops" ng-controller="HomeController">
<div class="row">
<div class="col-md-12">
<h1>\{\{title}}</h1>
<ng-Multiselect array-List="datas"></ng-Multiselect>
</div>
</div>
</div>

我很乐意帮助你

我发现的最快的解决方案是使用来自 角度滤波器角度滤波器filterBy过滤器,例如:

<input type="text" placeholder="Search by name or genre" ng-model="ctrl.search"/>
<ul>
<li ng-repeat="movie in ctrl.movies | filterBy: ['name', 'genre']: ctrl.search">
\{\{movie.name}} (\{\{movie.genre}}) - \{\{movie.rating}}
</li>
</ul>

好处是 角度滤波器角度滤波器是一个相当受欢迎的库(在 GitHub 上大约有2.6 k 颗星) ,它仍然在积极地开发和维护中,所以将它作为一个依赖项添加到您的项目中应该没有问题。

现在加入这个派对已经太晚了,但它可能会帮助到某人:

我们可以分两步来做,首先根据第一个属性进行过滤,然后根据第二个过滤器进行连接:

$scope.filterd = $filter('filter')($scope.empList, { dept: "account" });
$scope.filterd = $scope.filterd.concat($filter('filter')($scope.empList, { dept: "sales" }));

查看带有多个属性筛选器的工作提琴

选项1: 使用角度提供的滤波器比较器参数

// declaring a comparator method
$scope.filterBy = function(actual, expected) {
return _.contains(expected, actual); // uses underscore library contains method
};


var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];


// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')(employees, {name: ['a','c']}, $scope.filterBy);

选项2: 使用角度提供的滤波器否定

var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];


// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')($filter('filter')(employees, {name: '!d'}), {name: '!b'});