如何在angularJS中过滤多个值(OR运算)

时间:2013-04-07 21:48:33

标签: javascript angularjs angularjs-ng-repeat

我想在角度中使用filter并希望过滤多个值,如果它有任何一个值,则应显示它。

我有这样的结构:

对象movie,其属性为genres,我想要对ActionComedy进行过滤。

我知道我可以filter:({genres: 'Action'} || {genres: 'Comedy'}),但如果我想动态过滤该怎么办。例如。 filter: variableX

当我有一系列我需要过滤的类型时,如何在variableX中设置$scope

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

20 个答案:

答案 0 :(得分:85)

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

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>

修改这里是链接:Creating Angular Filters

更新:这是fiddle,其中包含我建议的精确演示。

答案 1 :(得分:77)

您可以使用控制器功能进行过滤。

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>

答案 2 :(得分:22)

在这里创建一个自定义过滤器可能有点过分,如果你有多个值,你可以传入一个自定义比较器:

$scope.selectedGenres = "Action, Drama"; 

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

然后在过滤器中:

filter:{name:selectedGenres}:containsComparator

答案 3 :(得分:17)

这是自定义过滤器的实现,它将使用值数组过滤数据。它将支持具有数组和单个键值的多个键对象。如上所述inangularJS API AngularJS filter Doc支持具有单个值的多个键过滤器,但是下面的自定义过滤器将支持与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]}

以下是实施上述“filterMutiple”自定义过滤器的小提琴示例。 :::Fiddle Example:::

答案 4 :(得分:13)

如果你想过滤对象阵列,你可以给出

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

将根据为该属性指定的特定过滤器过滤单个属性。

但是如果你想要通过单独的属性过滤和全局过滤所有属性,那么你可以做类似的事情。

<tr ng-repeat="supp in $data | filter : filterObject |  filter : search">
其中“filterObject”是用于搜索单个属性的对象,“Search”将在全局搜索每个属性。

〜阿图尔

答案 5 :(得分:9)

我花了一些时间在它上面,感谢@chrismarx,我看到角度的默认mask = (df['Date'] == some_date) & (df['Outbound Facility'] == some_outbound) filtered_df = df[mask] 允许你传递自己的比较器。这是编辑过的多个值的比较器:

filtered_df

如果我们想为DRY制作自定义过滤器:

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

最后这里是plunkr

注意:预期数组应该只包含简单对象,如字符串数字等。

答案 6 :(得分:7)

您可以使用angular.filter

的搜索字段过滤器

<强> IS

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

答案 7 :(得分:6)

我发现最快的解决方案是使用angular-filter中的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>

好处是angular-filter是一个相当受欢迎的库(GitHub上约2.6k星),它仍然在积极开发和维护,所以将它作为依赖项添加到项目中应该没问题。

答案 8 :(得分:6)

如果情况允许,您还可以使用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>

答案 9 :(得分:4)

我相信这就是你要找的东西:

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

答案 10 :(得分:2)

让我们假设您有两个数组,一个用于电影,一个用于流派

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

即可

这里作为数组和类型的流派具有流派的价值

答案 11 :(得分:2)

请试试这个

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

答案 12 :(得分:1)

角度或过滤模块

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

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

答案 13 :(得分:1)

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

<强> JS:

self.movingItem.frame = CGRect(x: movingItem.frame.origin.x + 5.0, 
                                            y: movingItem.frame.origin.y, 
                                            width: movingItem.frame.width, 
                                            height: movingItem.frame.height)

HTML:

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

答案 14 :(得分:1)

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

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>

答案 15 :(得分:1)

以下是我的示例如何为表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>

我很高兴,如果我帮助你

答案 16 :(得分:1)

参加聚会太晚了,但也许可以帮助某人:

我们可以分两步完成,首先按第一个属性过滤,然后通过第二个过滤器连接:

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

See the working fiddle with multiple property filter

答案 17 :(得分:0)

选项1: 使用Angular提供的过滤器比较器参数

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

选项2: 使用Angular提供的过滤器求反

{
    _id: "1",
    name: "test1",
    active: true,
    cars: [
       { _id: "2", name: "aaa", active: true },
       { _id: "3", name: "bbb", active: false },
       { _id: "4", name: "ccc", active: true },
},
{
    _id: "2",
    name: "test2",
    active: false,
    cars: [
       { _id: "10", name: "aaa", active: true }
}

答案 18 :(得分:-3)

我的解决方案

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

答案 19 :(得分:-15)

最好的答案是:

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