How to filter multiple values (OR operation) in angularJS

前端 未结 20 863
清酒与你
清酒与你 2020-11-22 10:01

I want to use the filter in angular and want to filter for multiple values, if it has either one of the values then it should be displayed.

I have for

相关标签:
20条回答
  • 2020-11-22 10:15

    Creating a custom filter might be overkill here, you can just pass in a custom comparator, if you have the multiples values like:

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

    then in the filter:

    filter:{name:selectedGenres}:containsComparator
    
    0 讨论(0)
  • 2020-11-22 10:15

    Angular Or Filter Module

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

    here is the link: https://github.com/webyonet/angular-or-filter

    0 讨论(0)
  • 2020-11-22 10:20

    I wrote this for strings AND functionality (I know it's not the question but I searched for it and got here), maybe it can be expanded.

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

    Usage:

    <li ng-repeat="x in array | filterMultiple:{key1: value1, key2:[value21, value22]}">{{x.name}}</li>
    
    0 讨论(0)
  • 2020-11-22 10:21

    The quickest solution that I've found is to use the filterBy filter from angular-filter, for example:

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

    The upside is that angular-filter is a fairly popular library (~2.6k stars on GitHub) which is still actively developed and maintained, so it should be fine to add it to your project as a dependency.

    0 讨论(0)
  • 2020-11-22 10:22

    You can use a controller function to filter.

    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>
    
    0 讨论(0)
  • 2020-11-22 10:23

    I've spent some time on it and thanks to @chrismarx, I saw that angular's default filterFilter allows you to pass your own comparator. Here's the edited comparator for multiple values:

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

    And if we want to make a custom filter for 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);
          };
        });
    

    And then we can use it anywhere we want:

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

    Finally here's a plunkr.

    Note: Expected array should only contain simple objects like String, Number etc.

    0 讨论(0)
提交回复
热议问题