【问题标题】:How to filter multiple values (OR operation) in angularJS如何在angularJS中过滤多个值(或运算)
【发布时间】:2013-03-29 21:27:53
【问题描述】:

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

例如,我有这样的结构:

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

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

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

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

【问题讨论】:

  • 您确定filter:({genres: 'Action'} || {genres: 'Comedy'}) 是否有效? angular 1.3.16 中没有。
  • 1.4.8 相同!它只是不起作用^^

标签: javascript angularjs angularjs-ng-repeat


【解决方案1】:

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

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,其中包含我的建议的精确演示。

【讨论】:

  • 那么在外面我返回我想要显示的电影对象?
  • 抱歉,我花了一段时间才回来。我用一个具体的例子更新了我的答案。
  • 好的,谢谢,在此期间我自己想通了,但它肯定会在以后帮助别人:)
  • 要么我有两个值,比如活动和非活动,那么我如何使用这个过滤器单独搜索。我们不想制作自定义过滤器。
【解决方案2】:

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

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>

【讨论】:

  • 除了关注点分离之外,是否有任何理由(性能方面)可以避免这种情况?
  • javascript 版本,如果其他人正在寻找它:$scope.filteredMovies = $filter('filter')($scope.movies, $scope.filterByGenres);
【解决方案3】:

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

$scope.selectedGenres = "Action, Drama"; 

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

然后在过滤器中:

filter:{name:selectedGenres}:containsComparator

【讨论】:

  • 帮了我很多。谢谢
  • @chrismarx ng-model 会在视图文件中以链接到所描述的过滤器吗? (抱歉,仍然在这里学习)——我喜欢你的简单回答并试图让它发挥作用,但不知道如何标记我的&lt;input&gt;ng-model。 :)
  • 你需要阅读这个 - docs.angularjs.org/api/ng/filter/filter
【解决方案4】:

这里是自定义过滤器的实现,它将使用值数组过滤数据。它将支持具有数组和单个键值的多个键对象。如前所述 inangularJS API AngularJS filter Doc 支持单个值的多个键过滤器,但下面的自定义过滤器将支持与 angularJS 相同的功能,并且还支持值数组以及数组和键值的组合。请在下面找到代码 sn-p ,

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

【讨论】:

  • 您似乎有正确的意图,但您的示例似乎没有按预期工作。表中的输出似乎相当不一致。
  • 这不适用于带有嵌套对象的 JSON。如果是这样就很理想了。它还会在控制台中触发length property undefined 错误。
  • 它对我有用,但如果它在列表中找不到搜索的属性,它会返回所有结果,如果值没有,我该如何反转这种行为并且不返回任何结果是否存在于列表中?
  • @ZakariaBelghiti 如果您不想返回任何结果,请将代码:if (fData.length &gt; 0){ this.filteredData = fData; } 更改为:this.filteredData = fData;
  • @Gerfried 我认为该网站实际上是在抓取 Stackoverflow,所以他们偷了他的答案,而不是反过来
【解决方案5】:

如果你想过滤对象数组,那么你可以给

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

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

但是,如果您想按单个属性进行过滤并针对所有属性进行全局过滤,那么您可以这样做。

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

~阿图尔

【讨论】:

【解决方案6】:

我花了一些时间,感谢@chrismarx,我看到 angular 的默认 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;
    }
  };

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

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>

最后是plunkr

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

【讨论】:

  • 感谢这对我有帮助。检查单个值 filterWithOr:{name:'Jack'} 如果有人需要和我一样...
【解决方案7】:

你可以使用angular.filter的searchField过滤器

JS:

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

【讨论】:

  • 你也可以使用angular.filter的“where” {{ obj.name }}
  • search 到此为止。
  • 我尝试了这个并在我的角度应用程序中设置了模块和我的索引 HTML 中的脚本,但我仍然能够搜索所有字段,而不仅仅是我指定的字段:(
【解决方案8】:

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

我发现最快的解决方案是使用来自angular-filterfilterBy 过滤器,例如:

<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 颗星),它仍在积极开发和维护,因此将它作为依赖项添加到您的项目中应该没问题。

【讨论】:

  • 迄今为止最好的答案。谢谢。
【解决方案10】:

我相信这就是您要找的:

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

【讨论】:

  • 它只是连接数组而不返回联合。
  • 除非我误解了实现,否则我看不出这是个问题。
【解决方案11】:

请试试这个

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】:

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

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

    这里的流派是数组,类型对流派有价值

    【讨论】:

      【解决方案13】:

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

      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>
      

      【讨论】:

        【解决方案14】:

        角度或过滤器模块

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

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

        【讨论】:

          【解决方案15】:

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

          JS:

          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>
          

          【讨论】:

            【解决方案16】:

            这是我如何为表 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>
            

            如果能帮到你我很高兴

            【讨论】:

              【解决方案17】:

              加入派对为时已晚,但可能对某人有帮助:

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

              $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

              【讨论】:

                【解决方案18】:

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

                // 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: 使用 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'});
                

                【讨论】:

                  【解决方案19】:

                  我的解决方案

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

                  【讨论】:

                  • 在 VS 2015 上检查过,它没有得到语法,它也不起作用
                  【解决方案20】:

                  最好的答案是:

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

                  【讨论】:

                  • 这不只是过滤“喜剧”吗?
                  • 我试过了,它只过滤“喜剧”,而不是“动作”。
                  猜你喜欢
                  • 1970-01-01
                  • 2014-02-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-02-24
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多