AngularJS - So erhalten Sie eine ngRepeat-gefilterte Ergebnisreferenz

129

Ich verwende eine ng-repeat-Direktive mit Filter wie folgt:

ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4"

und ich kann die gerenderten Ergebnisse gut sehen; Jetzt möchte ich eine Logik für dieses Ergebnis in meinem Controller ausführen. Die Frage ist, wie ich die Referenz der Ergebniselemente abrufen kann.

Aktualisieren:


Nur um zu verdeutlichen: Ich versuche, eine automatische Vervollständigung zu erstellen. Ich habe folgende Eingabe:

<input id="queryInput" ng-model="query" type="text" size="30" placeholder="Enter query">

und dann die gefilterten Ergebnisse:

<ul>
   <li  ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4">{{item.name}}</li>
</ul>

Jetzt möchte ich im Ergebnis navigieren und eines der Elemente auswählen.

Shlomi Schwartz
quelle

Antworten:

270

UPDATE : Hier ist ein einfacher Weg als zuvor.

 <input ng-model="query">
 <div ng-repeat="item in (filteredItems = (items | orderBy:'order_prop' | filter:query | limitTo:4))">
   {{item}}
 </div>

Dann $scope.filteredItemsist zugänglich.

Andrew Joslin
quelle
Vielen Dank für die Antwort, siehe mein Update. Wie würden Sie das implementieren, beachten Sie, dass ich die gesamte Artikelliste auf init
Shlomi Schwartz
super cool, danke dafür. Ich wünschte, es wäre ein eingebautes Feature von NG
Shlomi Schwartz
3
Das Problem bei diesem Ansatz ist, dass Sie beim Betrachten der zugewiesenen Eigenschaft am Ende $ digests spammen (eine pro Iteration) ... Vielleicht gibt es eine Möglichkeit, dies zu vermeiden?
Juho Vepsäläinen
1
Wenn ich mir das Suchobjekt und console.log ansehe, erhalte filteredItemsich die Daten immer einen Filter später. Es ist nicht das Ergebnis des gerade geänderten Filters, sondern das der vorherigen Änderung. Irgendwelche Ideen?
ProblemsOfSumit
4
Kann mir jemand erklären, warum das funktioniert? Ich kann verstehen, dass eine Variable aus dem $ scope im Wiederholungsbereich (Bereichsvererbung) zugänglich ist, aber umgekehrt? Wie? Einige Dokumentationen werden geschätzt. Danke
Dalvarezmartinez1
30

Hier ist die Filterversion von Andy Joslins Lösung.

Update: BREAKING CHANGE. Ab Version 1.3.0-beta.19 ( dieses Commit ) haben Filter keinen Kontext und thissind an den globalen Bereich gebunden. Sie können den Kontext entweder als Argument übergeben oder die neue Aliasing-Syntax in ngRepeat , 1.3.0-beta.17 + verwenden.

// pre 1.3.0-beta.19
yourModule.filter("as", function($parse) {
  return function(value, path) {
    return $parse(path).assign(this, value);
  };
});

// 1.3.0-beta.19+
yourModule.filter("as", function($parse) {
  return function(value, context, path) {
    return $parse(path).assign(context, value);
  };
});

Dann aus Ihrer Sicht

<!-- pre 1.3.0-beta.19 -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.19+ -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:this:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.17+ ngRepeat aliasing -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 as filteredItems">
 {{item}}
</div>

Welches gibt Ihnen Zugang zu $scope.filteredItems.

kevinjamesus86
quelle
Vielen Dank! Können Sie erklären, wie der Filtercode funktioniert? Ich bin mit $ parse nicht vertraut, und die eckigen Dokumente haben mir nicht geholfen, zu entschlüsseln, wie Ihr Filter genau funktioniert.
Magne
2
@Magne Kein Problem! Bitte schauen Sie sich das Update an, da es Ihnen später Schmerzen und Leiden ersparen kann. Zur Beantwortung Ihrer Frage, kurz gesagt, $parseist Angular des Ausdruck Compiler .. Zum Beispiel, es wird die Zeichenfolge ‚some.object.property‘ zu nehmen und gibt eine Funktion , die Sie zu jedem Satz erlaubt oder einen Wert auf dem Pfad für einen bestimmten erhalten Kontext. Ich verwende es, um hier speziell Filterergebnisse für den $ -Bereich festzulegen. Ich hoffe das beantwortet deine Frage.
Kevinjamesus86
23

Versuchen Sie so etwas. Das Problem mit der ng-Wiederholung besteht darin, dass ein untergeordneter Bereich erstellt wird, auf den Sie nicht zugreifen können

Filterelemente

von der Steuerung

<li ng-repeat="doc in $parent.filteritems = (docs | filter:searchitems)" ></li>
imal hasaranga perera
quelle
16

Aktualisieren:

Auch nach 1.3.0. Wenn Sie es in den Bereich des Controllers oder des übergeordneten Elements einfügen möchten, können Sie dies nicht als Syntax verwenden. Zum Beispiel, wenn ich folgenden Code habe:

<div>{{labelResults}}</div>
<li ng-repeat="label in (labels | filter:query | as labelResults)">
</div>

Das oben genannte wird nicht funktionieren. Der Weg, dies zu umgehen, besteht darin, das $ parent wie folgt zu verwenden :

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">
Gal Bracha
quelle
Es ist gut zu beachten, dass, wenn Sie ein LimitTo-Filter haben. Es wird nicht in den $ parent.labelResults
Zack
Wenn ich console.log labelResultsdie Daten immer einen Filter später bekomme. Es ist nicht das Ergebnis des gerade geänderten Filters, sondern das der vorherigen Änderung. Hattest du dieses Problem nicht?
Anna
10

Ich habe mir eine etwas bessere Version von Andys Lösung ausgedacht. In seiner Lösung setzt ng-repeat den Ausdruck, der die Zuordnung enthält, im Auge. Jede Digest-Schleife wertet diesen Ausdruck aus und weist das Ergebnis der Bereichsvariablen zu.

Das Problem bei dieser Lösung besteht darin, dass Sie möglicherweise auf Zuweisungsprobleme stoßen, wenn Sie sich in einem untergeordneten Bereich befinden. Dies ist der gleiche Grund, warum Sie einen Punkt im ng-Modell haben sollten .

Das andere, was mir an dieser Lösung nicht gefällt, ist, dass sie die Definition des gefilterten Arrays irgendwo im Ansichts-Markup vergräbt. Wenn es in Ihrer Ansicht oder auf Ihrem Controller an mehreren Stellen verwendet wird, kann es verwirrend werden.

Eine einfachere Lösung besteht darin, eine Uhr in Ihrem Controller auf eine Funktion zu setzen, die die Zuordnung vornimmt:

$scope.$watch(function () {
    $scope.filteredItems = $scope.$eval("items | orderBy:'order_prop' | filter:query | limitTo:4");
});

Diese Funktion wird während jedes Verdauungszyklus bewertet, sodass die Leistung mit der von Andy vergleichbar sein sollte. Sie können der Funktion auch eine beliebige Anzahl von Zuweisungen hinzufügen, um sie alle an einem Ort zu speichern, anstatt sie über die Ansicht zu verteilen.

In der Ansicht würden Sie nur die gefilterte Liste direkt verwenden:

<ul>
    <li  ng-repeat="item in filteredItems">{{item.name}}</li>
</ul>

Hier ist eine Geige, in der dies in einem komplizierteren Szenario gezeigt wird.

Dave Johnson
quelle
Super sauber und verschmutzt die Struktur nicht, schön!
Kuzyn
Diese Lösung ist perfekt für mich. Ich habe die Sammlung von ionic anstelle von ng repeat verwendet. Deshalb hat die akzeptierte Antwort bei mir nicht
funktioniert