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