Solucionado (ver solução)
Solucionado
(ver solução)
18
respostas

Dúvidas sobre Filter Filter

Bom dia

Achei muito interessante a funcionalidade do filter do angularjs. Ganha muito tempo na hora de implementar.

Segue exemplo implementado na aula:

ng-repeat="objeto in objetos | filter : filtro"

Essa função é muito interessante mas filtra por todos os atributos do objeto.

Existe uma forma de filtrar pelos atributos que eu escolher?

Pesquisei na internet e achei algo similar mas só funciona com apenas 1 atributo do objeto, segue exemplo:

ng-repeat="curso in cursos | filter : {'nome' : filtro}"

Preciso filtrar 3 atributos, sendo eles nome, localidade e instituição. Foi implementado como no exemplo abaixo mas algo esta errado:

ng-repeat="curso in cursos | filter : {'nome' : filtro, 'localidade' : filtro, 'instituicao' : filtro}"

Parabéns pelo curso

18 respostas

É verdade, só funciona com um atributo. O que você esta querendo aplicar é uma lógica de filtro própria, nesse caso pode criar uma função no seu controller aplicando uma lógica de programação super básica que filtre o array com o seu critério.

Exemplo de estrutura de código:

<div ng-repeat="item in itens | filter:meuFiltro()">
  {{ item }}
</div>

E no controller,

$scope.meuFiltro = function() {
   // retorna uma nova lista de items filtrando de acordo com algum critério.
}

Sucesso e bom estudo!

Interessante, mas ainda estou com uma dúvida:

Na minha aplicação quando carrega a página o ng-init se encarrega de buscar a lista de informações do backend.

Eu aplico o critério quando essa lista é gerada? Ou faço de outro forma?

Segue abaixo minha controller:

        $scope.init = function() {
            Evento.getAll(function(data) {
                $scope.eventos = data;
                //implementar o critério...
            }, function() {
                toastr.error(Messages('app.error'), Messages('app.angular.error'));
            });
        };

Você aplica na função de filtro que você vai criar. O que essa função faz é apenas retornar a nova lista filtrada para o ng-repeat. Ele nunca muda o arquivo original.

Um exemplo...

$scope.meuFiltro = function() {

       return $scope.eventos.filter(function(evento) {
          // lógica do seu filtro aqui
      });
};

Veja que no exemplo acima foi usada a já batida função filter do JavaScript para retornar um novo array seguindo a lógica que você quer aplicar. Lembre-se que na sua lógica você deve retorna true para que o elemento faça parte da nova lista, false para excluí-lo. Em nenhum momento a lista original é alterada.

Flavio ainda estou com dificuldades em como criar o critério, não sei se preciso passar o scope por parâmetro. Segue código abaixo:

        $scope.meuFiltro = function() {
            return ($scope.filtro);
        };

Essa parte do código funciona da mesma forma que a explicada no curso mas acho que nesse return preciso comparar com os atributos do objeto:

Por exemplo

$scope.meuFiltro = function() {
    return ('atributo1' === $scope.filtro || 'atributo2' === $scope.filtro );
};

procede essa lógica?

Opa! Acho que você postou antes de ver o pedaço de código que postei:

$scope.meuFiltro = function() {

       return $scope.eventos.filter(function(evento) {
          // lógica do seu filtro aqui
      });
};

É um filter básico do JavaScript mesmo,, não há nada de Angular nele. Basta agora no bloco da função acessar as propriedades de $scope que você precisa para realizar as comparações.

não tinha lido o post anterior!

vou fazer uns testes.

Então...

$scope.meuFiltro = function() {

       return $scope.eventos.filter(function(evento) {
            return evento.atributo1 == $scope.FiltroAtributo1 || evento.atributo2 == $scope.FiltroAtributo2
      });
};

Mas se quiser algo mais sofisticado, terá que usar expressão regular e por ai vai. A complexidade da lógica e o grau de paridade quem vai definir é você com seu algoritmo.

Montei o seguinte código:

        $scope.meuFiltro = function() {
            return $scope.eventos.filter(function(evento) {
                return evento.titulo === $scope.filtro;
            });
        };

Mas apresenta erro no navegador

Cannot read property 'filter' of undefined

Você não disse a linha do erro. Mas pelo o que você colocou, é um erro do JavaScript que indica que você esta chamando .filter em alguém que não existe.

Provavelmente você não inicializou $scope.eventos com um array em vazio, aliás, boa prática em JavaScript inicializar as variáveis que você vai utilizar.

Chuto que o filter esta sendo lido antes dos dados chegarem, por isso inicializar é importante.

Ou não existe $scope.eventos em seu $scope

É verdade, acabei esquecendo de inicializar a variável:

$scope.eventos = [];

ao iniciar a variável os erros pararam mas o filtro ainda não funciona.

Vou buscar uma outra forma de fazer e seguir o que você tinha indicado de expressão regular.

Vou dar mais uma estudada.

Muito obrigado pela ajuda.

Oi Haroldo! Eu te sabotei sem querer. Vejamos uma implementação do filtro para o projeto da Alurapic que você pode adaptar:

    $scope.meuFiltro = function(foto) {
        if($scope.filtro) {

            return foto.titulo.match(new RegExp($scope.filtro, 'gi')) ? true : false;
        }    
        return true;    
    }

Na função do filtro, não precisamos iterar na lista, ele recebe cada elemento automaticamente que você aplicará sua lógica.

Agora, para usar o filtro você faz assim:

ng-repeat="foto in fotos | filter: meuFiltro"

Agora você pode adaptar para o seu caso. Desculpe qualquer transtorno (eu confundi com a lógica de filtro do Angular 2...).

Acabei implementando dessa forma e funcionou!

      $scope.meuFiltro = function(evento) {

            if($scope.filtro) {
                return evento.nome.match(new RegExp($scope.filtro, 'gi')) ? true : false;
            }

            return true;
        };

Como você havia comentado a lista não precisa ser iterada mas além de filtrar pelo nome com essa lógica posso filtrar por mais atributos do objeto?

Como por exemplo localidade e Instituição?

Conseguimos filtrar pelo nome do evento mas consigo filtrar por localidade e instituição digitando no mesmo input?

Eu não queria filtrar a foto pela url, apenas pelos outros campos que são mais importantes para o usuário.

Se eu digitar http... ele vai filtrar pela url também e isso é meio estranho para quem vai acessar o sistema.

Ou uma lógica onde pode filtrar por quase todos os campos menos pela url.

Muito obrigado pela atenção.

No caso você vai colocar mais condições dentro da lógica do filter, um ou ||.

solução!

Segue um exemplo melhorado com dois testes. Digitei no smartphone mas parece que está ok.

      $scope.meuFiltro = function(foto) {
            var exp = new RegExp($scope.filtro, 'i');
            if($scope.filtro) {
                return exp.test(foto.titulo) || exp.test(foto.descricao);
            }
            // se não digitou no filtro exibe tudo
            return true;
        };

No exemplo anterior, crio a expressão regular para buscar por $sopé.filtro, independente se é maiúscula ou minúscula. Se retornar true, o item é exibido, se retornar false ele é oculto.

Boa tarde Flavio

Peço desculpas pela demora em responder.

Essa lógica funcionou muito bem.

Desde já agradeço pela ajuda.

Muito obrigado!

Excelente! Sucesso e bom estudo meu aluno!