¿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)?

Vural
fuente
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/

bmleite
fuente
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>
Valentyn Shybanov
fuente
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">
DenisKolodin
fuente
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> 
a8m
fuente
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>
ph6
fuente
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

ollix
fuente
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;
  };
Belgo Canadiense
fuente