Come filtrare più valori (operazione OR) in angularJS

Voglio usare il filter in angular e voglio filtrare per più valori, se ha uno dei valori che dovrebbe essere visualizzato.

Ho per esempio questa struttura:

Un movie object che ha i genres proprietà e voglio filtrare per Action e Comedy .

So che posso fare il filter:({genres: 'Action'} || {genres: 'Comedy'}) , ma cosa fare se voglio filtrarlo dynamicmente. Es. filter: variableX

Come imposto variableX in $scope , quando ho una matrice dei generi che devo filtrare?

Potrei costruirlo come una stringa e poi fare un eval() ma non voglio usare eval () …

Vorrei solo creare un filtro personalizzato. Non sono così difficili.

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

modello:

 

Movies

Action
Family
{{genrefilters.action}}::{{genrefilters.family}}
  • {{movie.title}}: {{movie.genre}}

Modifica qui è il collegamento: Creazione di filtri angolari

AGGIORNAMENTO : Ecco un violino che ha una demo esatta del mio suggerimento.

È ansible utilizzare una funzione controller per filtrare.

 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:

 
  • {{ movie.name }} {{ movie.genre }}

La creazione di un filtro personalizzato potrebbe essere eccessivo qui, puoi semplicemente passare in un comparatore personalizzato, se hai valori multipli come:

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

quindi nel filtro:

 filter:{name:selectedGenres}:containsComparator 

Ecco l’implementazione del filtro personalizzato, che filtrerà i dati utilizzando una matrice di valori. Supporterà più oggetti chiave con array e valore singolo di chiavi. Come menzionato inangularJS API AngularJS filter Doc supporta più filtri chiave con un singolo valore, ma sotto il filtro personalizzato supporterà la stessa funzionalità di angularJS e supporta anche array di valori e combinazione di array e valore singolo di chiavi.Per trovare lo snippet di codice qui sotto,

 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 0){ this.filteredData = fData; } } } }; if (keyObj){ angular.forEach(keyObj,function(obj,key){ filterObj.applyFilter(obj,key); }); } return filterObj.filteredData; } }]); 

Uso:

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

Ecco un esempio di violino con implementazione del filtro personalizzato “filterMutiple” sopra. ::: Fiddle Example :::

Se vuoi filtrare su Array of Objects allora puoi dare

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

La proprietà individuale verrà filtrata dal filtro specifico fornito per quella proprietà.

Ma se volevi qualcosa come il filtro per singola proprietà e il filtro globale per tutte le proprietà, allora puoi fare qualcosa di simile.

  

Ci ho dedicato un po ‘di tempo e grazie a @chrismarx ho visto che filterFilter di default di filterFilter ti consente di passare il tuo comparatore. Ecco il comparatore modificato per più valori:

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

E se vogliamo creare un filtro personalizzato per 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); }; }); 

E poi possiamo usarlo ovunque vogliamo:

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

Finalmente ecco un plunkr .

Nota: l’array previsto dovrebbe contenere solo oggetti semplici come String , Number ecc.

puoi usare il filtro searchField di angular.filter

JS:

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

HTML:

   {{ user.first_name }} {{ user.last_name }}   

Puoi anche usare ngIf se la situazione lo consente:

 
{{ p.name }} is cool

La soluzione più rapida che ho trovato è quella di utilizzare il filtro dal filtro angular , ad esempio:

  
  • {{movie.name}} ({{movie.genre}}) - {{movie.rating}}

Il lato positivo è che il filtro angular è una libreria abbastanza popolare (~ 2.6k stelle su GitHub) che è ancora triggersmente sviluppata e mantenuta, quindi dovrebbe essere bello aggiungerla al progetto come dipendenza.

Credo che questo sia quello che stai cercando:

 
{{ (collection | fitler1:args) + (collection | filter2:args) }}

Per favore prova questo

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

Supponiamo che tu abbia due array, uno per il film e uno per il genere

Usa semplicemente il filtro come: filter:{genres: genres.type}

Qui i generi sono l’array e il tipo ha un valore per il genere

Ho scritto questo per le stringhe e la funzionalità (so che non è la domanda ma l’ho cercata e sono arrivata qui), forse può essere espansa.

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

Uso:

 
  • {{x.name}}
  • Modulo angular o filtro

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

    ecco il link: https://github.com/webyonet/angular-or-filter

    Ho avuto una situazione simile. Scrivere filtri personalizzati ha funzionato per me. Spero che questo ti aiuti!

    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:

     
    • {{ movie.name }} {{ movie.genre }}

    Ecco il mio esempio come creare filtri e direttive per table jsfiddle

    direttiva ottenere lista (dati) e creare tabella con filtri

     

    {{title}}

    piacere se ti aiuto

    È troppo tardi per partecipare alla festa, ma potrebbe essere utile per qualcuno:

    Possiamo farlo in due fasi, prima filtrare prima la proprietà e poi concatenare con il secondo filtro:

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

    Guarda il violino funzionante con più filtri di proprietà

    La mia soluzione

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

    la migliore risposta è:

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