Como filtrar uma matriz com AngularJS e usar uma propriedade do objeto filtrado como o atributo ng-model?

121

Se eu tenho uma matriz de objetos e quero vincular o modelo Angular a uma propriedade de um dos elementos com base em um filtro, como faço isso? Eu posso explicar melhor com um exemplo concreto:

HTML:

<!DOCTYPE html>
<html ng-app>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
        <meta charset=utf-8 />
        <title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
        <input ng-model="results.year">
        <input ng-model="results.subjects.title | filter:{grade:'C'}">
    </body>
</html>

Controlador:

function MyCtrl($scope) {
  $scope.results = {
    year:2013,
    subjects:[
      {title:'English',grade:'A'},
      {title:'Maths',grade:'A'},
      {title:'Science',grade:'B'},
      {title:'Geography',grade:'C'}
    ]
  };
}

JSBin: http://jsbin.com/adisax/1/edit

Quero filtrar a segunda entrada para o assunto com uma nota 'C', mas não quero vincular o modelo à nota ; Quero vinculá-lo ao título do assunto que tem o grau 'C'.

Isso é possível? Em caso afirmativo, como é feito?

Bernhard Hofmann
fonte

Respostas:

127
<div ng-repeat="subject in results.subjects | filter:{grade:'C'}">
    <input ng-model="subject.title" />
</div>
JB Nizet
fonte
1
Eu vejo aonde você está indo com isso, mas eu realmente não queria um repetidor. A propriedade pela qual vou filtrar é uma coluna de identidade, por isso é única. Mas vejo que essa seria a maneira correta de resolver o problema genérico.
Bernhard Hofmann
1
este é um tutorial para os italianos :) dev.stasbranger.com/post/77190983049/…
Silvio Troia
10
isso foi muito útil e, por inverso (tudo que não fosse C), funcionaria:filter:{grade:'!'+'C'}
pulkitsinghal
2
Você pode fazer o mesmo com um grade array? No meu caso, eu construo minha matriz de notas a partir de uma visualização em árvore e quero filtrar o resultado para aqueles na matriz.
Juan Carlos Oropeza
157

Você pode usar o filtro "filter" no seu controlador para obter todas as notas "C". Obter o primeiro elemento da matriz de resultados fornecerá o título do assunto com a classificação "C".

$scope.gradeC = $filter('filter')($scope.results.subjects, {grade: 'C'})[0];

http://jsbin.com/ewitun/1/edit

O mesmo com o ES6 simples:

$scope.gradeC = $scope.results.subjects.filter((subject) => subject.grade === 'C')[0]
Oliver
fonte
me desculpe, eu não estou seguindo esse segundo filtro ('filtro'), você pode explicar um pouco mais?
Winnemucca 23/09
1
@stevek Esse é o nome do filtro. O método filter () fornece o filtro. É exatamente isso que o filtro é chamado de filtro porque filtra uma matriz. Ficaria assim com o filtro de moeda: $ filter ('currency') (valor, símbolo, tamanho da
Oliver
61

Aqui está um JSBin modificado com uma amostra de trabalho:

http://jsbin.com/sezamuja/1/edit

Aqui está o que eu fiz com os filtros na entrada:

<input ng-model="(results.subjects | filter:{grade:'C'})[0].title">
lukeatdesignworks
fonte
1
Este é o negócio real. Esse é o poder. Este é o caminho. Eu fui com isso e agora estou feliz.
user1576978
13

observe que, se você usar $ filter assim:

$scope.failedSubjects = $filter('filter')($scope.results.subjects, {'grade':'C'});

e você passou a ter outra nota para Oh, não sei, CC ou AC ou C + ou CCC que as atrai. você precisa anexar um requisito para uma correspondência exata:

$scope.failedSubjects = $filter('filter')($scope.results.subjects, {'grade':'C'}, true);

Isso realmente me matou quando eu estava puxando alguns detalhes da comissão como este:

var obj = this.$filter('filter')(this.CommissionTypes, { commission_type_id: 6}))[0];

só é chamado para um bug porque estava inserindo o ID da comissão 56 em vez de 6.

Adicionar as verdadeiras força uma correspondência exata.

var obj = this.$filter('filter')(this.CommissionTypes, { commission_type_id: 6}, true))[0];

Ainda assim, eu prefiro isso (eu uso o texto datilografado, daí o "Let" e =>):

let obj = this.$filter('filter')(this.CommissionTypes, (item) =>{ 
             return item.commission_type_id === 6;
           })[0];

Faço isso porque, em algum momento no caminho, talvez eu queira obter mais informações desses dados filtrados, etc ... ter a função ali dentro, meio que deixa o capô aberto.

Daniel Morris
fonte
Eu tive o mesmo erro como você, obrigado pela dica com o terceiro parâmetro booleano. Não estava ciente disso.
Georg Leber
12

se você quiser criar uma lista separada de resultados no controlador, poderá aplicar um filtro

function MyCtrl($scope, filterFilter) {
  $scope.results = {
    year:2013,
    subjects:[
      {title:'English',grade:'A'},
      {title:'Maths',grade:'A'},
      {title:'Science',grade:'B'},
      {title:'Geography',grade:'C'}
    ]
  };
  //create a filtered array of results 
  //with grade 'C' or subjects that have been failed
  $scope.failedSubjects = filterFilter($scope.results.subjects, {'grade':'C'});
}

Em seguida, você pode fazer referência a failSubjects da mesma maneira que referenciaria o objeto de resultados

você pode ler mais sobre isso aqui https://docs.angularjs.org/guide/filter

como esta resposta angular atualizou a documentação, eles agora recomendam chamar o filtro

// update 
// eg: $filter('filter')(array, expression, comparator, anyPropertyKey);
// becomes
$scope.failedSubjects = $filter('filter')($scope.results.subjects, {'grade':'C'});
Kieran
fonte
o que é filterFilter? é algum serviço ou diretiva? onde está o código para filterFilter?
Mou
é um serviço angular. Dê uma olhada no primeiro exemplo no link acima. (no arquivo scripts.js)
Kieran
embora eles mudaram a filterFilter documentação ainda funciona ..
Kieran
4

Você também pode usar funções com $filter('filter'):

var foo = $filter('filter')($scope.results.subjects, function (item) {
  return item.grade !== 'A';
});
Nelu
fonte
4

Se você estiver usando o ES6, poderá:

var sample = [1, 2, 3]

var result = sample.filter(elem => elem !== 2)

/* output */
[1, 3]

Além disso, observe que o filtro não atualiza a matriz existente; ela retornará uma nova matriz filtrada sempre.

Diego Venâncio
fonte
0

Aplicando o mesmo filtro em HTML com várias colunas, apenas um exemplo:

 variable = (array | filter : {Lookup1Id : subject.Lookup1Id, Lookup2Id : subject.Lookup2Id} : true)
Amay Kulkarni
fonte