Como filtrar múltiplos valores (operação OR) em angularJS

Eu quero usar o filter em angular e deseja filtrar por vários valores, se ele tiver um dos valores, ele deve ser exibido.

Eu tenho por exemplo essa estrutura:

Um movie object que tem os genres propriedade e eu quero filtrar para Action e Comedy .

Eu sei que posso fazer filter:({genres: 'Action'} || {genres: 'Comedy'}) , mas o que fazer se eu quiser filtrá-lo dinamicamente. Por exemplo, filter: variableX

Como faço para definir variableX no $scope , quando eu tenho uma matriz dos gêneros que eu tenho que filtrar?

Eu poderia construí-lo como uma string e, em seguida, fazer um eval() mas eu não quero usar eval () …

Gostaria apenas de criar um filtro personalizado. Eles não são tão difíceis.

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

modelo:

 

Movies

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

Edite aqui o link: Criando Filtros Angulares

ATUALIZAÇÃO : Aqui está um violino que tem uma demonstração exata da minha sugestão.

Você pode usar uma function de controlador para filtrar.

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

Criar um filtro personalizado pode ser um exagero aqui, você pode simplesmente passar um comparador personalizado, se você tiver múltiplos valores como:

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

então no filtro:

 filter:{name:selectedGenres}:containsComparator 

Aqui está a implementação do filtro personalizado, que irá filtrar os dados usando matriz de valores. Ele irá suportar vários objects-chave com matriz e valor único de chaves. Como mencionado no filtro inangularJS API AngularJS, o Doc suporta vários filtros de chave com valor único, mas o filtro personalizado abaixo suportará o mesmo recurso que o angularJS e também suporta matriz de valores e combinação de matriz e valor único de chaves.Por favor, encontre o trecho de código abaixo,

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

Aqui está um exemplo de violino com a implementação do filtro personalizado “filterMutiple” acima. ::: Exemplo de violino :::

Se você quiser filtrar Array of Objects, então você pode dar

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

Propriedade individual será filtrada pelo filtro específico dado para essa propriedade.

Mas se você quiser algo como filtrar por Propriedade individual e filtrar globalmente para todas as propriedades, poderá fazer algo assim.

  

Passei algum tempo nisso e, graças ao @chrismarx, vi que o filterFilter padrão do angular permite que você passe seu próprio comparador. Aqui está o comparador editado para vários valores:

  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 quisermos fazer um filtro personalizado para 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 então podemos usá-lo em qualquer lugar que quisermos:

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

Finalmente aqui está um plunkr .

Nota: A matriz esperada deve conter apenas objects simples, como String , Number etc.

você pode usar o filtro searchField de 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 }}   

Você também pode usar ngIf se a situação permitir:

 
{{ p.name }} is cool

A solução mais rápida que encontrei é usar o filtro filterBy filtro angular , por exemplo:

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

A vantagem é que o angular-filter é uma biblioteca bastante popular (~ 2.6k estrelas no GitHub) que ainda está ativamente desenvolvida e mantida, então deve ser bom adicioná-la ao seu projeto como uma dependência.

Eu acredito que isso é o que você está procurando:

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

Por favor tente isto

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

Vamos supor que você tem dois arranjos, um para o filme e outro para o gênero

Basta usar o filtro como: filter:{genres: genres.type}

Aqui os gêneros que são a matriz e o tipo têm valor para o gênero

Eu escrevi isso para strings e funcionalidade (eu sei que não é a questão, mas eu procurei por ele e cheguei aqui), talvez ele possa ser expandido.

 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}}
  • Módulo angular ou de filtro

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

    aqui está o link: https://github.com/webyonet/angular-or-filter

    Eu tive uma situação semelhante. Escrever um filtro personalizado funcionou para mim. Espero que isto ajude!

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

    Aqui está o meu exemplo como criar filtro e diretiva para a tabela jsfiddle

    diretiva obter lista (datas) e criar tabela com filtros

     

    {{title}}

    meu prazer se eu te ajudar

    Tarde demais para participar da festa, mas pode ser que possa ajudar alguém:

    Podemos fazer isso em duas etapas, primeiro filtrar pela primeira propriedade e depois concatenar pelo segundo filtro:

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

    Veja o violino de trabalho com vários filtros de propriedades

    Minha solução

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

    a melhor resposta é:

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