Wie filtere (Schlüssel, Wert) mit ng-repeat in AngularJs?


113

Ich versuche etwas zu tun wie:

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

AngularJs Teil:

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

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

Aber irgendwie zeigt es mir alle Gegenstände. Wie kann ich filtern (Schlüssel, Wert)?


Bitte geben Sie einige Beispieldaten für Artikel an. Oder gib uns eine Geige;)
Robin Drexler

Auf diese Weise erstellen Sie keinen Filterblick auf die Dokumentationen , und wie Robin sagte, bitte ein Beispiel.
Yahya KACEM

Ich habe bereits ein vollständiges Beispiel gegeben und weiß, wie man Filter verwendet. Ich frage nur "wie man Filter mit (Schlüssel, Wert) verwendet".
Vural

Index und Anzahl sollten in diesem Bereich verfügbar sein iirc
Shanimal

Antworten:


131

Winkel Filter können nur auf Arrays und nicht Objekte angewendet werden, von Winkel API -

"Wählt eine Teilmenge von Elementen aus dem Array aus und gibt sie als neues Array zurück."

Hier haben Sie zwei Möglichkeiten:
1) Verschieben $scope.itemsin ein Array oder -
2) Vorfiltern der ng-repeatElemente wie folgt:

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

Und auf dem Controller:

$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
Bei diesem Ansatz muss man vorsichtig sein, um Endlosschleifen (Digest-Schleifen) zu vermeiden. Siehe 6054 und 705 . Zusammenfassung von Narretz : Kurz gesagt, die Verwendung von Funktionen zum Zurückgeben der Sammlung in ng-repeat ist ein Anti-Pattern. Es ist besser, die Sammlung einer Bereichseigenschaft zuzuweisen und diese zu durchlaufen.
Joe23

3
Hilfreicher Kommentar. Dies warf mich für eine Schleife; Ich hatte erwartet, dass ich jedes iterable filtern kann . Vielen Dank. :)
Chris Krycho

3
Hinweis: Dies ist jetzt ein perfektes Anti-Muster. Angular 1.3 verfügt jetzt über zustandslose Filter ( egghead.io/lessons/… ), daher möchten Sie auf jeden Fall einen Filter dafür erstellen.
Kentcdodds

8
@kentcdodds poste keine Links, die nicht kostenlos sind!
Sebastian

11
Warum nicht einfach ein ng-if zum wiederholten Element hinzufügen?
CarbonDry

45

Meine Lösung wäre, einen benutzerdefinierten Filter zu erstellen und diesen zu verwenden:

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

Und in HTML:

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

1
Es wird jedoch n * n-mal wiederholt.
Maxisam

27

Sie können auch verwenden ng-repeatmit ng-if:

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

2
Klug. Das hat viel Zeit gespart.
Safwan


11

Sie können einfach das Modul angle.filter verwenden und dann sogar nach verschachtelten Eigenschaften filtern.
siehe: jsbin
2 Beispiele:

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
Sie sollten offenlegen, dass dies angular.filterkein Kernwinkelmodul ist und Sie der Autor davon sind.
Demisx

Es sieht so aus, als ob der toArrayFilter nicht mehr vorhanden ist. Gibt es einen Ersatz, weil der filterFilter immer noch keine Objekte zulässt?
Tryse

6

Es ist etwas spät, aber ich habe nach einem ähnlichen Filter gesucht und so etwas beendet:

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

2
Wie haben Sie das zum Laufen gebracht? Wenn ich einen Filter mit einem ng-wiederholten Objekt verwende, wird ein Fehler angezeigt, der aufgrund der Angular-Dokumentation erwartet wird.
Tonstrike

1

Obwohl diese Frage ziemlich alt ist, möchte ich meine Lösung für Entwickler von Angular 1 teilen. Der Punkt ist, nur den ursprünglichen Winkelfilter wiederzuverwenden, aber alle Objekte transparent als Array zu übergeben.

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

benutze es so:

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

Hier ist ein Plunker


0

Ich habe ein bisschen mehr von einem generischen Filter gemacht, den ich bereits in mehreren Projekten verwendet habe:

  • Objekt = das Objekt, das gefiltert werden muss
  • Feld = das Feld innerhalb des Objekts, nach dem gefiltert wird
  • filter = Der Wert des Filters, der mit dem Feld übereinstimmen muss

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;
  };
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.