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

Vural
la source
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/

bmleite
la source
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>
Valentyn Shybanov
la source
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">
DenisKolodin
la source
2
Intelligent. Cela a permis de gagner beaucoup de temps.
Safwan
21

Ou utilisez simplement

ng-show="v.hasOwnProperty('secId')"

Voir la solution mise à jour ici:

http://jsfiddle.net/RFontana/WA2BE/93/

Renaud
la source
1
Merci .. J'ai utilisé ceci mais avec à la ng-ifplace
Zim
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> 
a8m
la source
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>
ph6
la source
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

ollix
la source
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;
  };
BelgoCanadien
la source