Angular ng-repeat pula um item se ele corresponder à expressão

91

Estou procurando uma maneira de dizer basicamente ao angular para pular um item em uma repetição do ng se ele corresponder a uma expressão, basicamente continue;

No controlador:

$scope.players = [{
    name_key:'FirstPerson', first_name:'First', last_name:'Person'
}, {
    name_key:'SecondPerson', first_name:'Second', last_name:'Person'
}]

Agora, em meu modelo, quero mostrar a todos que não correspondem name_key='FirstPerson'. Achei que deviam ser filtros, então configurei um Plunkr para brincar com ele, mas não tive sorte. Plunkr Attempt

aron.duby
fonte
Eu tento entender: você quer mostrar todos os itens, mas apontar quem combina e quem não é? ou apenas filtrar?
Maxim Shoustin

Respostas:

144

Como @Maxim Shoustin sugeriu, a melhor maneira de conseguir o que você deseja é usar um filtro personalizado.
Mas há outras maneiras, uma delas é usar a ng-ifdiretiva no mesmo elemento em que você colocou a ng-repeatdiretiva (também, aqui está o plunker ):

<ul>
    <li ng-repeat="player in players" ng-if="player.name_key!='FirstPerson'"></li>
</ul>

Isso pode representar uma pequena desvantagem do ponto de vista estético, mas tem a grande vantagem de que sua filtragem pode ser baseada em uma regra que não é tão fortemente acoplada à playersmatriz e que pode acessar facilmente outros dados no escopo do seu aplicativo:

  <li 
      ng-repeat="player in players" 
      ng-if="app.loggedIn && player.name != user.name"
  ></li>

Atualização
Conforme dito, esta é uma das soluções para este tipo de problema e pode ou não atender às suas necessidades.
Conforme apontado nos comentários, ng-ifé uma diretiva, o que na verdade significa que ela pode fazer mais coisas em segundo plano do que você espera.
Por exemplo, ng-if cria um novo escopo de seu pai :

O escopo criado no ngIf herda de seu escopo pai usando a herança prototípica.

Isso geralmente não afeta o comportamento normal, mas para evitar casos inesperados, você deve ter isso em mente antes de implementar.

gion_13
fonte
isso era exatamente o que eu estava procurando, sabia que deveria haver uma maneira curta e doce de fazer isso sem o filtro personalizado. Obrigado!
aron.duby
Nota: existem alguns comportamentos de escopo de ng-if que podem ser complicados. Tentei esse método e causou problemas em outro lugar. Ou seja, eu tenho uma diretiva de "observador" que transmite um evento quando o repetidor termina. Depois de adicionar o ng-if a este repetidor, ele não disparou mais aquele evento. Um filtro personalizado pode ser a maneira mais limpa de ir.
claywhipkey
@claywhipkey você está certo, a maneira mais limpa é usando um filtro, mas isso não é adequado para todos os casos. De qualquer forma, thx pelo comentário e você pode ver que eu adicionei um heads-up atualização na resposta apenas para fazer alguém consciente das implicações do uso de uma directiva para a filtragem de dados.
gion_13
43

Sei que é antigo, mas caso alguém procure outra solução possível, aqui está outra forma de resolver isso - use a funcionalidade de filtro padrão :

Objeto: um objeto padrão pode ser usado para filtrar propriedades específicas em objetos contidos em array. Por exemplo, o predicado {name: "M", phone: "1"} retornará uma matriz de itens que possuem o nome da propriedade contendo "M" e a propriedade phone contendo "1". ... O predicado pode ser negado prefixando a string com!. Por exemplo, o predicado {name: "! M"} retornará uma matriz de itens que possuem o nome da propriedade que não contém "M".

Portanto, para o exemplo de TS, algo como isto deve fazer:

<ul>
    <li ng-repeat="player in players | filter: { name_key: '!FirstPerson' }"></li>
</ul>

Não há necessidade de escrever filtros personalizados, nem de usar ng-ifcom seu novo escopo.

Ilya Luzyanin
fonte
Simples ao ponto. Nenhum filtro personalizado ou novo escopo criado como o autor declarou. Perfeito para pular um único valor em uma lista.
mbokil
Eu acho que você precisa omitir o 'player' de 'player.name_key' - então seria apenas "{name_key: '! FirstPerson'}" no exemplo acima.
smithml
Nunca consegui fazer o Angular tocar bem com teclas vazias. Existe algum tipo de truque para usar os filtros integrados para o equivalente a player in players | filter: { name_key: '' }? Essa diretiva específica não corresponderá apenas a jogadores sem / um vazio name_key. O inverso, name_key: '!'destinado a selecionar qualquer jogador com um não vazio name_keytambém não funcionará.
Eric L.
Você pode verificar esta resposta.
Ilya Luzyanin
4
Esteja ciente de que isso só funciona com matrizes, não com propriedades de objeto em um caso comong-repeat="(key, val) in player"
David Diez
19

Você pode usar o filtro personalizado ao implementar ng-repeat. Algo como:

 data-ng-repeat="player in players |  myfilter:search.name

myfilter.js:

app.filter('myfilter', function() {


   return function( items, name) {
    var filtered = [];

    angular.forEach(items, function(item) {

      if(name == undefined || name == ''){
        filtered.push(item);
        }

      /* only if you want start With*/
      // else if(item.name_key.substring(0, name.length) !== name){
      //   filtered.push(item);
      // }

      /* if you want contains*/
      // else if(item.name_key.indexOf(name) < 0 ){
      //   filtered.push(item);
      // }

       /* if you want match full name*/
       else if(item.name_key !== name ){
        filtered.push(item);
      }
    });

    return filtered;
  };
});

Demo Plunker

Maxim Shoustin
fonte
Obrigado pelo trabalho que você colocou nisso. Definitivamente correto, mas acabei obtendo a facilidade da resposta @ gion_13 no código, então achei melhor marcar a resposta dele como aceita
aron.duby