Come visualizzare la lunghezza dei dati filtrati ng-repeat


438

Ho un array di dati che contiene molti oggetti (formato JSON). Quanto segue può essere assunto come contenuto di questo array:

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

Ora, visualizzo questi dettagli come:

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

Qui, la query è modellata su un campo di input in cui l'utente può limitare i dati visualizzati.

Ora, ho un'altra posizione in cui visualizzo il conteggio attuale delle persone / persone visualizzate, ad es Showing {{data.length}} Persons

Quello che voglio fare è che quando l'utente cerca una persona e i dati visualizzati vengono filtrati in base alla query, Showing...personscambia anche il valore delle persone mostrate al momento. Ma non sta succedendo. Visualizza sempre il totale delle persone nei dati anziché quello filtrato: come posso ottenere il conteggio dei dati filtrati?

Risposte:


746

Per Angular 1.3+ (crediti a @Tom)

Usa un'espressione alias (Documenti: Angolare 1.3.0: ngRipeti , scorri verso il basso fino alla sezione Argomenti ):

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

Per angolare prima di 1.3

Assegnare i risultati a una nuova variabile (ad es. filtered) E accedervi:

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

Visualizza il numero di risultati:

Showing {{filtered.length}} Persons

Fiddle un esempio simile . I crediti vanno a Pawel Kozlowski


42
Questa è la risposta semplice che non ripete l'esecuzione del filtro.
agmin

3
@Ben: Sì. È possibile accedervi all'interno del controller utilizzando $scope.filtered.length.
Wumms,

2
Questo non funziona per me. Registri undefined, probabilmente perché al momento della registrazione, la variabile non è stata ancora definita. Quindi, come posso assicurarmi che il codice nel controller venga eseguito dopo che la variabile è stata definita e il filtro è stato applicato nella vista?
Ben

6
@Ben: suppongo che questo sia fuori tema. Prenderei in considerazione la creazione di un filtro personalizzato, ad esempio jsfiddle , tuttavia, potresti anche guardarlo all'interno del controller:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms

3
La versione 1.3 e versioni successive non ha funzionato se volevo aggiungere limitTo: person in data | filter:query as filtered | limitTo:5. Quindi ho dovuto usare la versione 1.3 precedente:person in filtered = (data | filter: query) | limitTo: 5
benjovanic il

333

Per completezza, oltre alle risposte precedenti (eseguire il calcolo delle persone visibili all'interno del controller) è anche possibile eseguire tali calcoli nel modello HTML come nell'esempio seguente.

Supponendo che il tuo elenco di persone sia datavariabile e che filtri le persone utilizzando il querymodello, il seguente codice funzionerà per te:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - stampa il numero totale di persone
  • {{(data|filter:query).length}} - stampa il numero filtrato di persone

Si noti che questa soluzione funziona correttamente se si desidera utilizzare i dati filtrati una sola volta in una pagina. Tuttavia, se si utilizzano i dati filtrati più di una volta, ad es. Per presentare elementi e mostrare la lunghezza dell'elenco filtrato, suggerirei di utilizzare l' espressione alias (descritta di seguito) per AngularJS 1.3+ o la soluzione proposta da @Wumms per AngularJS versione precedente alla 1.3.

Nuova funzione in angolare 1.3

I creatori di AngularJS hanno anche notato quel problema e nella versione 1.3 (beta 17) hanno aggiunto l'espressione "alias" che memorizzerà i risultati intermedi del ripetitore dopo l'applicazione dei filtri, ad es.

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

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

L' espressione alias impedirà il problema dell'esecuzione di più filtri.

Spero che possa essere d'aiuto.


4
Questo significa che il filtro viene eseguito due volte?
Flash

9
Sì, viene eseguito due volte.
nathancahill,

11
assicurati di leggere la risposta @Wumms prima di decidere di usare questo (e non lo farai) ...
epeleg

1
Non importa, vedo che la risposta non conteneva la parte relativa all'espressione alias quando hai fatto il tuo commento.
Adam Goodwin,

2
Questa risposta supporta più espressioni di filtro a differenza dell'attuale risposta principale. cioè){{(data|filter:query|filter:query2).length}}
chakeda

45

Il modo più semplice se lo hai

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

Lunghezza dei dati filtrati

<div>{{ (data | filter: query).length }}</div>

Questo è molto utile per chiunque usi la direttiva dir-paginate utils angolari in quanto l'aliasing e l'alternativa pre ng-1.3 non sono supportati.
PCnate,

Questo enumererà i dati due volte?
Jeppe,

36

ngRepeat crea una copia dell'array quando applica un filtro, quindi non è possibile utilizzare l'array di origine per fare riferimento solo agli elementi filtrati.

Nel tuo caso, in potrebbe essere meglio applicare il filtro all'interno del controller utilizzando il $filterservizio:

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

  $scope.filteredData = myNormalData;

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

  // ...
}

E poi usi invece la filteredDataproprietà nella tua vista. Ecco un Plunker funzionante: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview


1
Quello che ho capito è che uso {{filteredData.length}}invece di data.length. Ho anche capito che myInputModelè il modello mappato alla query di input che filtra i dati. valsarebbe il testo che viene digitato nell'input (sostanzialmente query) ma ogni volta che scrivo, cambia. Ma cosa c'è filterFilterqui? Potrei aggiungere che ho creato il mio filtro personalizzato (in cui posso specificare quale chiave dell'oggetto considerare per il filtro).
user109187

Giusto. Utilizzalo anche ng-repeat="person in filteredData"perché non ha senso filtrarlo due volte. Con il $filterservizio, è possibile chiedere un filtro specifico da solo suffisso con "filtro", ad esempio: dateFilter, jsonFilter, ecc Se si sta utilizzando il proprio filtro personalizzato, basta usare quella invece del generico filterFilter.
Josh David Miller,

Che ne dici di applicare più filtri a un ng-repeat, diciamo che hai 2 menu a discesa con valori e un campo di inserimento testo?
alchemication

Il filtro è solo una funzione, quindi passeresti semplicemente l'output del primo filtro al secondo filtro.
Josh David Miller,

29

Da AngularJS 1.3 è possibile utilizzare gli alias:

item in items | filter:x as results

e da qualche parte:

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

Da documenti :

È inoltre possibile fornire un'espressione alias facoltativa che memorizzerà quindi i risultati intermedi del ripetitore dopo l'applicazione dei filtri. In genere, viene utilizzato per visualizzare un messaggio speciale quando un filtro è attivo sul ripetitore, ma il set di risultati filtrati è vuoto.

Ad esempio: oggetto in oggetti | filtro: x come risultati memorizzerà il frammento degli elementi ripetuti come risultati, ma solo dopo che gli articoli sono stati elaborati attraverso il filtro.


Non riesco ad applicare $scope.$watcha questo risultato con alias. Qualche suggerimento per $broadcasting la resultsvariabile con alias ?
DeBraid,

25

È anche utile notare che è possibile memorizzare più livelli di risultati raggruppando i filtri

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>

ecco un violino demo


13

Ecco un esempio funzionante Vedi su 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;
  });
});


4
Il problema con questo approccio è che stai eseguendo il filtro due volte: una volta in ngRepeat e una volta nel controller.
Josh David Miller,

Sì, hai ragione, puoi pubblicare il tuo esempio di lavoro in base alla tua risposta, vorrei imparare un po 'più di filtri? Grazie.
Maksym

2
Sicuro. Ecco il Plunker funzionante: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview . Ho appena modificato il tuo.
Josh David Miller,

10

Puoi farlo in 2 modi . Nel modello e nel controller . Nel modello è possibile impostare l'array filtrato su un'altra variabile, quindi utilizzarlo come si desidera. Ecco come farlo:

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

Se hai bisogno di esempi, vedi gli esempi / demo di conteggio filtrati di AngularJs

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.