So zeigen Sie die Länge der gefilterten ng-repeat-Daten an

438

Ich habe ein Datenarray, das viele Objekte enthält (JSON-Format). Als Inhalt dieses Arrays kann Folgendes angenommen werden:

var data = [
  {
    "name": "Jim",
    "age" : 25
  },
  {
    "name": "Jerry",
    "age": 27
  }
];

Jetzt zeige ich diese Details wie folgt an:

<div ng-repeat="person in data | filter: query">
</div

Hier wird die Abfrage in ein Eingabefeld modelliert, in dem der Benutzer die angezeigten Daten einschränken kann.

Jetzt habe ich einen anderen Ort, an dem ich die aktuelle Anzahl der angezeigten Personen / Personen anzeige, d. H. Showing {{data.length}} Persons

Was ich tun möchte, ist, dass, wenn der Benutzer nach einer Person sucht und die angezeigten Daten basierend auf der Abfrage gefiltert werden, sich Showing...personsauch der Wert der aktuell angezeigten Personen ändert. Aber es passiert nicht. Es werden immer die Gesamtzahl der Personen in den Daten angezeigt und nicht die gefilterten. Wie erhalte ich die Anzahl der gefilterten Daten?

user109187
quelle

Antworten:

746

Für Angular 1.3+ (Credits für @Tom)

Verwenden Sie einen Alias-Ausdruck (Docs: Angular 1.3.0: ngRepeat , scrollen Sie nach unten zum Abschnitt Argumente ):

<div ng-repeat="person in data | filter:query as filtered">
</div>

Für Angular vor 1.3

Weisen Sie die Ergebnisse einer neuen Variablen zu (z. B. filtered) und greifen Sie darauf zu:

<div ng-repeat="person in filtered = (data | filter: query)">
</div>

Zeigen Sie die Anzahl der Ergebnisse an:

Showing {{filtered.length}} Persons

Geige ein ähnliches Beispiel . Credits gehen an Pawel Kozlowski

Wumms
quelle
42
Dies ist die einfache Antwort, die die Filterausführung nicht wiederholt.
Agmin
3
@ Ben: Ja. Sie können innerhalb des Controllers mit darauf zugreifen $scope.filtered.length.
Wumms
2
Das funktioniert bei mir nicht. Protokolle undefined, wahrscheinlich, weil die Variable zum Zeitpunkt der Protokollierung noch nicht definiert ist. Wie würde ich also sicherstellen, dass der Code in der Steuerung ausgeführt wird, nachdem die Variable definiert und der Filter in der Ansicht angewendet wurde?
Ben
6
@ Ben: Ich denke, das geht vom Thema ab. Ich würde in Betracht ziehen, einen benutzerdefinierten Filter zu erstellen , z. B. jsfiddle . Sie können ihn jedoch auch im Controller ansehen:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms
3
Die Version 1.3+ funktionierte nicht, wenn ich limitTo hinzufügen wollte : person in data | filter:query as filtered | limitTo:5. Also musste ich die Version vor 1.3 verwenden:person in filtered = (data | filter: query) | limitTo: 5
benjovanic
332

Der Vollständigkeit halber können Sie zusätzlich zu früheren Antworten (Berechnung der sichtbaren Personen innerhalb des Controllers durchführen) diese Berechnungen auch in Ihrer HTML-Vorlage durchführen, wie im folgenden Beispiel.

Angenommen, Ihre Personenliste ist datavariabel und Sie filtern Personen anhand des queryModells. Der folgende Code funktioniert für Sie:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - druckt die Gesamtzahl der Personen
  • {{(data|filter:query).length}} - druckt die gefilterte Anzahl von Personen

Beachten Sie, dass diese Lösung einwandfrei funktioniert, wenn Sie gefilterte Daten nur einmal auf einer Seite verwenden möchten . Wenn Sie jedoch gefilterte Daten mehrmals verwenden, z. B. um Elemente anzuzeigen und die Länge der gefilterten Liste anzuzeigen , würde ich empfehlen, den Alias-Ausdruck (unten beschrieben) für AngularJS 1.3+ oder die von @Wumms für AngularJS vor 1.3 vorgeschlagene Lösung zu verwenden.

Neues Feature in Angular 1.3

AngularJS-Ersteller bemerkten auch dieses Problem und fügten in Version 1.3 (Beta 17) den Ausdruck "Alias" hinzu, der die Zwischenergebnisse des Repeaters speichert, nachdem die Filter angewendet wurden, z

<div ng-repeat="person in data | filter:query as results">
    <!-- template ... -->
</div>

<p>Number of visible people: {{results.length}}</p>

Der Alias-Ausdruck verhindert das Problem der Ausführung mehrerer Filter.

Ich hoffe das wird helfen.

Tom
quelle
4
Bedeutet dies, dass der Filter zweimal ausgeführt wird?
Flash
9
Ja, es wird zweimal ausgeführt.
Nathancahill
11
Stellen Sie sicher, dass Sie die Antwort von @Wumms lesen, bevor Sie sich für diese entscheiden (und Sie werden es nicht
tun
1
Egal, ich sehe, dass die Antwort nicht den Teil über den Alias-Ausdruck enthielt, als Sie Ihren Kommentar abgegeben haben.
Adam Goodwin
2
Diese Antwort unterstützt im Gegensatz zur aktuellen Top-Antwort mehrere Filterausdrücke. dh){{(data|filter:query|filter:query2).length}}
Chakeda
45

Der einfachste Weg, wenn Sie haben

<div ng-repeat="person in data | filter: query"></div>

Gefilterte Datenlänge

<div>{{ (data | filter: query).length }}</div>
ionescho
quelle
Dies ist am nützlichsten für alle, die die Direkt-Paginate-Direktive von Angular Utils verwenden, da das Aliasing und die Alternative vor ng-1.3 nicht unterstützt werden.
PCNATE
Wird dies die Daten zweimal aufzählen?
Jeppe
36

ngRepeat erstellt eine Kopie des Arrays, wenn ein Filter angewendet wird. Sie können das Quellarray also nicht verwenden, um nur auf die gefilterten Elemente zu verweisen.

In Ihrem Fall ist es möglicherweise besser, den Filter mithilfe des $filterDienstes in Ihrem Controller anzuwenden :

function MainCtrl( $scope, filterFilter ) {
  // ...

  $scope.filteredData = myNormalData;

  $scope.$watch( 'myInputModel', function ( val ) {
    $scope.filteredData = filterFilter( myNormalData, val );
  });

  // ...
}

Und dann verwenden Sie filteredDatastattdessen die Eigenschaft in Ihrer Ansicht. Hier ist ein funktionierender Plunker: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview

Josh David Miller
quelle
1
Was ich verstanden, dass ich {{filteredData.length}}statt data.length. Ich habe auch verstanden, dass dies myInputModeldas Modell ist, das der Eingabeabfrage zugeordnet ist, die die Daten filtert. valwäre der Text, der in die Eingabe eingegeben wird (im Grunde Abfrage), aber jedes Mal, wenn ich tippe, ändert er sich. Aber was ist filterFilterhier? Ich könnte hinzufügen, dass ich meinen eigenen customFilter erstellt habe (wobei ich angeben kann, welcher Schlüssel des Objekts für die Filterung berücksichtigt werden soll).
user109187
Das stimmt. Verwenden Sie ng-repeat="person in filteredData"es auch einfach, da es keinen Sinn macht, es zweimal zu filtern. Mit dem $filterService können Sie für einen bestimmten Filter fragen nach suffixing es nur mit „Filter“, zum Beispiel: dateFilter, jsonFilterusw. Wenn Sie Ihre eigenen benutzerdefinierten Filter verwenden, verwenden Sie nur , dass man anstelle der allgemeinen filterFilter.
Josh David Miller
Was ist mit dem Anwenden mehrerer Filter auf eine ng-Wiederholung? Angenommen, Sie haben 2 Dropdowns mit Werten und ein Texteingabefeld?
Alchemie
Der Filter ist nur eine Funktion, sodass Sie nur die Ausgabe des ersten Filters an den zweiten Filter übergeben.
Josh David Miller
29

Seit AngularJS 1.3 können Sie Aliase verwenden:

item in items | filter:x as results

und irgendwo:

<span>Total {{results.length}} result(s).</span>

Aus Dokumenten :

Sie können auch einen optionalen Alias-Ausdruck bereitstellen, in dem die Zwischenergebnisse des Repeaters gespeichert werden, nachdem die Filter angewendet wurden. In der Regel wird dies verwendet, um eine spezielle Nachricht zu rendern, wenn ein Filter auf dem Repeater aktiv ist, die gefilterte Ergebnismenge jedoch leer ist.

Zum Beispiel: Artikel in Artikeln | filter: x as results speichert das Fragment der wiederholten Elemente als Ergebnisse, jedoch erst, nachdem die Elemente durch den Filter verarbeitet wurden.

Willkommen zu
quelle
Ich kann mich nicht $scope.$watchauf dieses Alias-Ergebnis bewerben . Irgendwelche Tipps für $broadcastdie Alias- resultsVariable?
DeBraid
25

Es ist auch nützlich zu beachten, dass Sie mehrere Gruppenebenen speichern können, indem Sie Filter gruppieren

all items: {{items.length}}
filtered items: {{filteredItems.length}}
limited and filtered items: {{limitedAndFilteredItems.length}}
<div ng-repeat="item in limitedAndFilteredItems = (filteredItems = (items | filter:search) | limitTo:25)">...</div>

Hier ist eine Demo-Geige

JeremyWeir
quelle
13

Hier ist Beispiel gearbeitet Siehe auf Plunker

  <body ng-controller="MainCtrl">
    <input ng-model="search" type="text">
    <br>
    Showing {{data.length}} Persons; <br>
    Filtered {{counted}}
    <ul>
      <li ng-repeat="person in data | filter:search">
        {{person.name}}
      </li>
    </ul>
  </body>

<script> 
var app = angular.module('angularjs-starter', [])

app.controller('MainCtrl', function($scope, $filter) {
  $scope.data = [
    {
      "name": "Jim", "age" : 21
    }, {
      "name": "Jerry", "age": 26
    }, {
      "name": "Alex",  "age" : 25
    }, {
      "name": "Max", "age": 22
    }
  ];

  $scope.counted = $scope.data.length; 
  $scope.$watch("search", function(query){
    $scope.counted = $filter("filter")($scope.data, query).length;
  });
});

Maksym
quelle
4
Das Problem bei diesem Ansatz ist, dass Sie den Filter zweimal ausführen: einmal im ngRepeat und einmal im Controller.
Josh David Miller
Ja, Sie haben Recht, können Sie Ihr Arbeitsbeispiel basierend auf Ihrer Antwort veröffentlichen. Ich möchte ein bisschen mehr Filter lernen. Vielen Dank.
Maksym
2
Sicher. Hier ist der funktionierende Plunker: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview . Ich habe gerade deine bearbeitet.
Josh David Miller
10

Sie können es auf zwei Arten tun . In Vorlage und in Controller . In der Vorlage können Sie Ihr gefiltertes Array auf eine andere Variable setzen und dann wie gewünscht verwenden. So geht's:

<ul>
  <li data-ng-repeat="user in usersList = (users | gender:filterGender)" data-ng-bind="user.name"></li>
</ul>
 ....
<span>{{ usersList.length | number }}</span>

Wenn Sie Beispiele benötigen, lesen Sie die AngularJs-Beispiele / Demos für die gefilterte Anzahl

Hazarapet Tunanyan
quelle