¿Cómo filtrar (clave, valor) con ng-repeat en AngularJs?


113

Estoy tratando de hacer algo como:

<div ng-controller="TestCtrl">
    <div ng-repeat="(k,v) in items | filter:hasSecurityId">
        {{k}} {{v.pos}}
    </div>
</div>

Parte de AngularJs:

function TestCtrl($scope) 
{
    $scope.items = {
                     'A2F0C7':{'secId':'12345', 'pos':'a20'},
                     'C8B3D1':{'pos':'b10'}
                   };

    $scope.hasSecurityId = function(k,v)
    {
       return v.hasOwnProperty('secId');
    }
}

Pero de alguna manera, me muestra todos los elementos. ¿Cómo puedo filtrar por (clave, valor)?


proporcione algunos datos de ejemplo para los elementos. O danos un violín;)
Robin Drexler

No es así como se crea un filtro para mirar las documentaciones y, como dijo Robin, un ejemplo, por favor.
Yahya KACEM

Ya di un ejemplo completo y sé cómo usar filtros. Solo estoy preguntando "cómo usar el filtro con (clave, valor)".
Vural

índice y recuento deben estar disponibles en ese ámbito iirc
Shanimal

Respuestas:


131

Los filtros angulares solo se pueden aplicar a matrices y no a objetos, desde la API de angular -

"Selecciona un subconjunto de elementos de la matriz y lo devuelve como una nueva matriz".

Aquí tiene dos opciones:
1) mover $scope.itemsa una matriz o -
2) prefiltrar los ng-repeatelementos, como este:

<div ng-repeat="(k,v) in filterSecId(items)">
    {{k}} {{v.pos}}
</div>

Y en el controlador:

$scope.filterSecId = function(items) {
    var result = {};
    angular.forEach(items, function(value, key) {
        if (!value.hasOwnProperty('secId')) {
            result[key] = value;
        }
    });
    return result;
}

jsfiddle : http://jsfiddle.net/bmleite/WA2BE/


9
Hay que tener cuidado con este enfoque para evitar bucles infinitos (resumen). Ver 6054 y 705 . Resumen de Narretz : En resumen, usar funciones para devolver la colección en ng-repeat es un anti-patrón. Es mejor asignar la colección a una propiedad de alcance y recorrerla.
Joe23

3
Comentario útil. Esto me estaba tirando por un bucle; Esperaba poder filtrar cualquier iterable. Muchas gracias. :)
Chris Krycho

3
Nota: Este es un anti-patrón perf ahora. Angular 1.3 ahora tiene filtros sin estado ( egghead.io/lessons/… ) por lo que definitivamente querrás crear un filtro para esto.
kentcdodds

8
¡@kentcdodds no publica enlaces que no sean gratuitos!
Sebastian

11
¿Por qué no agregar un ng-if en el elemento repetido?
CarbonDry

45

Mi solución sería crear un filtro personalizado y usarlo:

app.filter('with', function() {
  return function(items, field) {
        var result = {};
        angular.forEach(items, function(value, key) {
            if (!value.hasOwnProperty(field)) {
                result[key] = value;
            }
        });
        return result;
    };
});

Y en html:

 <div ng-repeat="(k,v) in items | with:'secId'">
        {{k}} {{v.pos}}
 </div>

1
sin embargo, se repetirá n * n veces.
maxisam

27

También puedes usarlo ng-repeatcon ng-if:

<div ng-repeat="(key, value) in order" ng-if="value > 0">

2
Inteligente. Esto ahorró mucho tiempo.
Safwan


11

Simplemente puede usar el módulo angular.filter , y luego puede filtrar incluso por propiedades anidadas.
ver: jsbin
2 Ejemplos:

JS:

angular.module('app', ['angular.filter'])
  .controller('MainCtrl', function($scope) {
  //your example data
  $scope.items = { 
    'A2F0C7':{ secId:'12345', pos:'a20' },
    'C8B3D1':{ pos:'b10' }
  };
  //more advantage example
  $scope.nestedItems = { 
    'A2F0C7':{
      details: { secId:'12345', pos:'a20' }
    },
    'C8B3D1':{
      details: { pos:'a20' }
    },
    'F5B3R1': { secId:'12345', pos:'a20' }
  };
});

HTML:

  <b>Example1:</b>
  <p ng-repeat="item in items | toArray: true | pick: 'secId'">
    {{ item.$key }}, {{ item }}
  </p>

  <b>Example2:</b>
  <p ng-repeat="item in nestedItems | toArray: true | pick: 'secId || details.secId' ">
    {{ item.$key }}, {{ item }}
  </p> 

21
Debe revelar que angular.filterno es un módulo angular central y que usted es el autor del mismo.
demisx

Parece que el toArrayfiltro ya no está presente. ¿Hay algún recambio, porque el filterfiltro todavía no admite objetos?
Trysis

6

Es un poco tarde, pero busqué un filtro similar y terminé usando algo como esto:

<div ng-controller="TestCtrl">
 <div ng-repeat="(k,v) in items | filter:{secId: '!!'}">
   {{k}} {{v.pos}}
 </div>
</div>

2
¿Cómo conseguiste que esto funcionara? Cuando uso un filtro con un objeto repetido ng, obtengo un error que es lo que se espera según la documentación de Angular.
Tonostrike

1

Aunque esta pregunta es bastante antigua, me gustaría compartir mi solución para desarrolladores de angular 1. El punto es simplemente reutilizar el filtro angular original, pero pasando de forma transparente cualquier objeto como una matriz.

app.filter('objectFilter', function ($filter) {
    return function (items, searchToken) {
        // use the original input
        var subject = items;

        if (typeof(items) == 'object' && !Array.isArray(items)) {
            // or use a wrapper array, if we have an object
            subject = [];

            for (var i in items) {
                subject.push(items[i]);
            }
        }

        // finally, apply the original angular filter
        return $filter('filter')(subject, searchToken);
    }
});

úsalo así:

<div>
    <input ng-model="search" />
</div>
<div ng-repeat="item in test | objectFilter : search">
    {{item | json}}
</div>

aquí hay un plunker


0

Hice un filtro un poco más genérico que ya he usado en varios proyectos:

  • objeto = el objeto que necesita ser filtrado
  • campo = el campo dentro de ese objeto por el que filtraremos
  • filtro = el valor del filtro que debe coincidir con el campo

HTML:

<input ng-model="customerNameFilter" />
<div ng-repeat="(key, value) in filter(customers, 'customerName', customerNameFilter" >
   <p>Number: {{value.customerNo}}</p>
   <p>Name: {{value.customerName}}</p>
</div>

JS:

  $scope.filter = function(object, field, filter) {
    if (!object) return {};
    if (!filter) return object;

    var filteredObject = {};
    Object.keys(object).forEach(function(key) {
      if (object[key][field] === filter) {
        filteredObject[key] = object[key];
      }
    });

    return filteredObject;
  };
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.