angular ng-repeat omite un elemento si coincide con la expresión

91

Estoy buscando una manera de decirle básicamente a angular que omita un elemento en una repetición ng si coincide con una expresión, básicamente continue;

En controlador:

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

Ahora, en mi plantilla, quiero mostrarles a todos los que no coinciden name_key='FirstPerson'. Pensé que tenían que ser filtros, así que configuré un Plunkr para jugar con él, pero no he tenido suerte. Intento de Plunkr

aron.duby
fuente
Trato de entender: ¿quieres mostrar todos los elementos pero señalar quién coincide y quién no? o simplemente filtrar?
Maxim Shoustin

Respuestas:

144

Como sugirió @Maxim Shoustin , la mejor manera de lograr lo que desea sería usar un filtro personalizado.
Pero hay otras formas, una de ellas es usar la ng-ifdirectiva en el mismo elemento donde colocó la ng-repeatdirectiva (también, aquí está el plunker ):

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

Esto puede presentar una pequeña desventaja desde una perspectiva estética, pero tiene la gran ventaja de que su filtrado podría basarse en una regla que no está tan estrechamente acoplada a la playersmatriz y que puede acceder fácilmente a otros datos en el alcance de su aplicación:

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

Actualización
Como se indicó, esta es una de las soluciones para este tipo de problema y puede que se adapte a sus necesidades o no.
Como se señaló en los comentarios, ng-ifes una directiva, lo que en realidad significa que podría hacer más cosas en segundo plano de lo que cabría esperar.
Por ejemplo, ng-if crea un nuevo alcance a partir de su padre :

El alcance creado dentro de ngIf hereda de su alcance padre usando herencia prototípica.

Por lo general, esto no afecta el comportamiento normal, pero para evitar casos inesperados, debe tener esto en cuenta antes de implementar.

gion_13
fuente
esto era exactamente lo que estaba buscando, sabía que tenía que haber una forma breve y sencilla de hacerlo sin el filtro personalizado. ¡Gracias!
aron.duby
Nota: hay algunos comportamientos de alcance de ng-if que pueden ser complicados. Probé este método y causó problemas en otros lugares. Es decir, tengo una directiva de "observador" que transmite un evento cuando el repetidor está terminado. Después de agregar el ng-if a este repetidor, ya no disparó ese evento. Un filtro personalizado podría ser la forma más limpia de hacerlo.
Claywhipkey
@claywhipkey tienes razón, la forma más limpia es usar un filtro, pero eso no es adecuado para todos los casos. De todos modos, thx por el comentario y se puede ver que he añadido un mano a mano de actualización en la respuesta sólo para hacer cualquier persona consciente de las consecuencias de utilizar una directiva para el filtrado de datos.
gion_13
43

Sé que esto es antiguo, pero en caso de que alguien busque otra posible solución, aquí hay otra forma de resolver esto: use la funcionalidad de filtro estándar :

Objeto: un objeto de patrón se puede utilizar para filtrar propiedades específicas en objetos contenidos por matriz. Por ejemplo, el predicado {nombre: "M", teléfono: "1"} devolverá una matriz de elementos cuyo nombre de propiedad contiene "M" y teléfono de propiedad que contiene "1". ... El predicado se puede negar anteponiendo la cadena con!. Por ejemplo, el predicado {name: "! M"} devolverá una matriz de elementos que tienen un nombre de propiedad que no contiene "M".

Entonces, para el ejemplo de TS, algo como esto debería funcionar:

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

No es necesario escribir filtros personalizados, no es necesario usarlos ng-ifcon su nuevo alcance.

Ilya Luzyanin
fuente
Simple al grano. No se ha creado un filtro personalizado o un nuevo alcance como ha indicado el autor. Perfecto para omitir un solo valor en una lista.
mbokil
Creo que debe omitir el 'jugador' de 'player.name_key', por lo que sería simplemente "{name_key: '! FirstPerson'}" en el ejemplo anterior.
smithml
Nunca pude hacer que Angular jugara bien con teclas vacías. ¿Existe algún tipo de truco para usar los filtros integrados para el equivalente de player in players | filter: { name_key: '' }? Esa directiva en particular no coincidirá solo con los jugadores con no / an vacío name_key. La inversa, name_key: '!'destinada a seleccionar cualquier jugador con un no vacío name_keytampoco funcionará.
Eric L.
Puedes comprobar esta respuesta.
Ilya Luzyanin
4
Tenga en cuenta que esto solo funciona con matrices, no con propiedades de objeto en un caso como ng-repeat="(key, val) in player"
David Diez
19

Puede utilizar un filtro personalizado al 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;
  };
});

Manifestación Plunker

Maxim Shoustin
fuente
Gracias por el trabajo que pusiste en esto. Es definitivamente correcto, pero terminé yendo con la facilidad de @ gion_13 en el código, así que pensé que
sería