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

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

bmleite
quelle
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>
Valentyn Shybanov
quelle
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">
DenisKolodin
quelle
2
Klug. Das hat viel Zeit gespart.
Safwan
21

Oder einfach benutzen

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

Die aktualisierte Lösung finden Sie hier:

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

Renaud
quelle
1
Danke .. Ich habe dies aber ng-ifstattdessen mit
Zim
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> 
a8m
quelle
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>
ph6
quelle
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

ollix
quelle
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;
  };
BelgoCanadian
quelle