Comment filtrer (clé, valeur) avec ng-repeat dans AngularJs?


113

J'essaye de faire quelque chose comme:

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

Partie AngularJs:

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

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

Mais d'une manière ou d'une autre, il me montre tous les articles. Comment filtrer sur (clé, valeur)?


Veuillez fournir des exemples de données pour les éléments. Ou donnez-nous un violon;)
Robin Drexler

Ce n'est pas ainsi que vous créez un filtre pour regarder les documentations , et comme l'a dit Robin, un exemple s'il vous plaît.
Yahya KACEM

J'ai déjà donné un exemple complet et je sais utiliser les filtres. Je demande simplement "comment utiliser le filtre avec (clé, valeur)".
Vural

l'index et le nombre devraient être disponibles dans cette étendue iirc
Shanimal

Réponses:


131

Les filtres angulaires ne peuvent être appliqués qu'aux tableaux et non aux objets, à partir de l'API angular -

"Sélectionne un sous-ensemble d'éléments du tableau et le renvoie en tant que nouveau tableau."

Vous avez deux options ici:
1) déplacer $scope.itemsvers un tableau ou -
2) pré-filtrer les ng-repeatéléments, comme ceci:

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

Et sur le contrôleur:

$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
Il faut être prudent avec cette approche pour éviter les boucles infinies (digest). Voir 6054 et 705 . Résumé par Narretz : En bref, utiliser des fonctions pour renvoyer la collection en ng-repeat est un anti-pattern. Il est préférable d'assigner la collection à une propriété d'étendue et de faire une boucle dessus.
Joe23

3
Commentaire utile. Cela me jetait pour une boucle; Je m'attendais à pouvoir filtrer tout itérable. Merci beaucoup. :)
Chris Krycho

3
Remarque: Il s'agit maintenant d'un anti-pattern de perf. Angular 1.3 a maintenant des filtres sans état ( egghead.io/lessons/… ) donc vous voudrez certainement créer un filtre pour cela.
kentcdodds

8
@kentcdodds ne publie pas de liens qui ne sont pas gratuits!
Sebastian

11
Pourquoi ne pas simplement ajouter un ng-if sur l'élément répété?
CarbonDry

45

Ma solution serait de créer un filtre personnalisé et de l'utiliser:

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;
    };
});

Et en html:

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

1
cependant, il bouclera n * n fois.
maxisam

27

Vous pouvez également utiliser ng-repeatavec ng-if:

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

2
Intelligent. Cela a permis de gagner beaucoup de temps.
Safwan


11

Vous pouvez simplement utiliser le module angular.filter , puis vous pouvez filtrer même par propriétés imbriquées.
voir: jsbin
2 Exemples:

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
Vous devez indiquer qu'il angular.filterne s'agit pas d'un module angulaire principal et que vous en êtes l'auteur.
demisx

Il semble que le toArrayfiltre n'est plus présent. Y a-t-il un remplacement, car le filterfiltre ne permet toujours pas les objets?
trysis

6

Il est un peu tard, mais j'ai cherché un filtre similaire et j'ai fini par utiliser quelque chose comme ceci:

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

2
Comment avez-vous réussi à faire fonctionner cela? Lorsque j'utilise un filtre avec un objet répété ng, j'obtiens une erreur qui est ce qui est attendu sur la base de la documentation Angular.
tonestrike

1

Bien que cette question soit plutôt ancienne, j'aimerais partager ma solution pour les développeurs angular 1. Le but est de simplement réutiliser le filtre angulaire d'origine, mais en passant de manière transparente tous les objets sous forme de tableau.

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);
    }
});

utilisez-le comme ceci:

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

voici un plunker


0

J'ai fait un peu plus d'un filtre générique que j'ai déjà utilisé dans plusieurs projets:

  • object = l'objet qui doit être filtré
  • field = le champ dans cet objet sur lequel nous filtrerons
  • filter = la valeur du filtre qui doit correspondre au champ

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;
  };
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.