Comment filtrer les valeurs multiples (ou fonctionnement) en angularJS

je veux utiliser le filter dans angulaire et souhaitez filtrer pour plusieurs valeurs, si elle a une des valeurs, alors il devrait être affiché.

j'ai par exemple cette structure:

Un objet movie qui a la propriété genres et je veux filtre pour Action et Comedy .

je sais que je peux faire filter:({genres: 'Action'} || {genres: 'Comedy'}) , mais que faire si je veux filtrer dynamiquement. E. g. filter: variableX

comment définir variableX dans le $scope , quand j'ai un tableau des genres que je dois filtrer?

je pourrais le construire comme une chaîne et ensuite faire un eval() mais je ne veux pas utiliser eval()...

126
demandé sur JustGoscha 2013-04-08 01:48:33

19 réponses

je créerais juste un filtre personnalisé. Ils ne sont pas si difficile.

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

modèle:

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

Modifier voici le lien: Création Angulaire Filtres

UPDATE : voici un fiddle qui a une démo exacte de ma suggestion.

80
répondu Xesued 2014-06-25 21:55:59

vous pouvez utiliser une fonction de contrôleur pour filtrer.

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>
77
répondu jlareau 2013-04-08 01:00:27

créer un filtre personnalisé pourrait être exagéré ici, vous pouvez simplement passer dans un comparateur personnalisé, si vous avez les valeurs multiples comme:

$scope.selectedGenres = "Action, Drama"; 

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

puis dans le filtre:

filter:{name:selectedGenres}:containsComparator
22
répondu chrismarx 2013-09-03 14:09:55

Voici l'implémentation du filtre personnalisé, qui va filtrer les données en utilisant un tableau de valeurs.Il soutiendra l'objet clé multiple avec le tableau et la valeur unique des clés. Comme mentionné INANGULARJS API AngularJS filter Doc prend en charge plusieurs filtre clé avec une seule valeur, mais au-dessous de filtre personnalisé prendra en charge la même fonctionnalité que angularJS et prend également en charge le tableau des valeurs et la combinaison des deux tableaux et la valeur unique des clés.S'il vous plaît trouver l'extrait de code ci-dessous,

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

Utilisation:

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

voici un exemple de violon avec la mise en œuvre de ci-dessus " filterMutiple " filtre personnalisé. :::Violon Exemple:::

17
répondu Nirmal Kumar VeluPillai 2014-03-28 23:08:47

si vous voulez filtrer sur un tableau D'objets alors vous pouvez donner

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

propriété individuelle sera filtré par un filtre particulier donné pour cette propriété.

mais si vous vouliez quelque chose comme filtrer par propriété individuelle et filtrer globalement pour toutes les propriétés, alors vous pouvez faire quelque chose comme ça.

<tr ng-repeat="supp in $data | filter : filterObject |  filter : search">
Où "filterObject" est un objet pour la recherche d'une propriété individuelle et "Search" va chercher dans chaque propriété à l'échelle mondiale.

~Atul

11
répondu user1941574 2016-09-15 21:37:01

j'ai passé du temps dessus et grâce à @chrismarx, j'ai vu que le défaut de cet angular filterFilter vous permet de passer votre propre comparateur. Voici le comparateur modifié pour les valeurs multiples:

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

Et si nous voulons faire un filtre personnalisé pour SEC:

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

et ensuite nous pouvons l'utiliser où nous voulons:

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

enfin voici un plunkr .

Note: tableau ne doit contenir que des objets simples comme Chaîne , Nombre etc.

9
répondu s.alem 2015-06-23 15:56:06

vous pouvez utiliser le filtre searchField de angulaire.filtre

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 -->
7
répondu a8m 2014-07-23 06:54:05

vous pouvez également utiliser ngIf si la situation le permet:

<div ng-repeat="p in [
 { name: 'Justin' }, 
 { name: 'Jimi' }, 
 { name: 'Bob' }
 ]" ng-if="['Jimi', 'Bob'].indexOf(e.name) > -1">
 {{ p.name }} is cool
</div>
6
répondu cyberwombat 2015-09-28 19:56:47

la solution la plus rapide que j'ai trouvée est d'utiliser le filtre filterBy de filtre angulaire , par exemple:

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

La hausse que angulaires-le filtre est un assez populaire de bibliothèque (~2.6 k étoiles sur GitHub) qui est toujours activement développé et maintenu, il devrait être bon pour l'ajouter à votre projet en tant que dépendance.

6
répondu Priidu Neemre 2016-09-13 22:06:33

je crois que c'est ce que vous cherchez:

<div>{{ (collection | fitler1:args) + (collection | filter2:args) }}</div>
4
répondu jKlaus 2014-07-11 14:17:32

s'il vous Plaît essayer cette

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;
    }
}]);
2
répondu rajeshpanwar 2015-06-24 10:51:58

laisse supposer que vous avez deux tableaux, un pour le film et un pour le genre

il suffit d'utiliser le filtre comme: filter:{genres: genres.type}

Ici, les genres, le tableau et le type a de la valeur pour le genre

2
répondu Amit Yadav 2016-01-02 13:37:47

j'ai écrit ceci pour les chaînes et la fonctionnalité (je sais que ce n'est pas la question mais je l'ai cherché et je suis arrivé ici), peut-être qu'il peut être élargi.

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

Utilisation:

<li ng-repeat="x in array | filterMultiple:{key1: value1, key2:[value21, value22]}">{{x.name}}</li>
1
répondu Uri 2014-10-30 01:09:52

Module Angulaire Ou Filtre

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

voici le lien: https://github.com/webyonet/angular-or-filter

1
répondu Burak Demirezen 2014-12-10 14:09:18

j'ai eu une situation similaire. L'écriture de filtre personnalisé a fonctionné pour moi. Espérons que cette aide!

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>
1
répondu hari nair 2015-06-30 18:57:50

Voici mon exemple comment créer un filtre et une directive pour la table jsfiddle

directive obtenir la liste (données) et de créer une table avec les filtres

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

mon plaisir si je vous aide

1
répondu Jasmin Kurtic 2016-08-08 10:17:53

trop tard pour rejoindre le parti, mais peut - être qu'il peut aider quelqu'un:

nous pouvons le faire en deux étapes, d'abord filtrer par première propriété, puis concaténer par deuxième filtre:

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

voir le violon de travail avec filtre à propriétés multiples

1
répondu Ali Adravi 2017-05-24 20:19:42

ma solution

ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"
-3
répondu Wilson Di Mateo 2015-06-18 17:56:01

la meilleure réponse est :

filter:({genres: 'Action', genres: 'Comedy'}
-15
répondu Chinaxing 2014-03-21 09:09:34