Jak wyświetlić długość przefiltrowanych danych z powtórzeniami ng


438

Mam tablicę danych, która zawiera wiele obiektów (format JSON). Jako zawartość tej tablicy można założyć:

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

Teraz wyświetlam te szczegóły jako:

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

Tutaj zapytanie jest modelowane do pola wejściowego, w którym użytkownik może ograniczyć wyświetlane dane.

Teraz mam inną lokalizację, w której wyświetlam bieżącą liczbę wyświetlanych osób / osób, tj Showing {{data.length}} Persons

Chcę, aby gdy użytkownik szukał osoby, a wyświetlane dane były filtrowane na podstawie zapytania, Showing...personszmieniałem również wartość wyświetlanych osób. Ale tak się nie dzieje. Zawsze wyświetla całkowitą liczbę osób w danych zamiast filtrowanej - jak uzyskać liczbę odfiltrowanych danych?

Odpowiedzi:


746

Dla Angular 1.3+ (podziękowania dla @Tom)

Użyj wyrażenia aliasowego (Docs: Angular 1.3.0: ngPowtórz , przewiń w dół do sekcji Argumenty ):

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

Dla Angulara przed 1.3

Przypisz wyniki do nowej zmiennej (np. filtered) I uzyskaj do niej dostęp:

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

Wyświetl liczbę wyników:

Showing {{filtered.length}} Persons

Fiddle podobny przykład . Kredyty należą do Pawła Kozłowskiego


42
To prosta odpowiedź, która nie powtarza wykonania filtra.
agmin

3
@Ben: Tak. Możesz uzyskać do niego dostęp za pomocą kontrolera $scope.filtered.length.
Wumms,

2
To mi nie działa. Dzienniki undefined, prawdopodobnie dlatego, że w momencie logowania zmienna nie jest jeszcze zdefiniowana. Jak więc upewnić się, że kod w kontrolerze jest uruchamiany po zdefiniowaniu zmiennej i zastosowaniu filtra w widoku?
Ben

6
@Ben: Myślę, że to nie na temat. Zastanowiłbym się nad stworzeniem niestandardowego filtra, np. Jsfiddle , można jednak również obejrzeć go w kontrolerze:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms

3
Wersja 1.3 + nie działa, jeśli chciałem dodać limitTo: person in data | filter:query as filtered | limitTo:5. Musiałem więc użyć wcześniejszej wersji 1.3:person in filtered = (data | filter: query) | limitTo: 5
benjovanic

332

Dla kompletności, oprócz poprzednich odpowiedzi (wykonaj obliczenia widocznych osób wewnątrz kontrolera), możesz również wykonać te obliczenia w szablonie HTML, jak w poniższym przykładzie.

Zakładając, że twoja lista osób jest datazmienna, a ty filtrujesz ludzi za pomocą querymodelu, następujący kod będzie dla ciebie działał:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - drukuje całkowitą liczbę osób
  • {{(data|filter:query).length}} - drukuje przefiltrowaną liczbę osób

Pamiętaj, że to rozwiązanie działa dobrze, jeśli chcesz użyć przefiltrowanych danych tylko raz na stronie. Jeśli jednak użyjesz przefiltrowanych danych więcej niż raz, np. Do prezentacji elementów i wyświetlenia długości przefiltrowanej listy, sugerowałbym użycie wyrażenia aliasowego (opisanego poniżej) dla AngularJS 1.3+ lub rozwiązania zaproponowanego przez @Wumms dla AngularJS w wersji wcześniejszej niż 1.3.

Nowa funkcja w Angular 1.3

Twórcy AngularJS również zauważyli ten problem, aw wersji 1.3 (beta 17) dodali wyrażenie „alias”, które będzie przechowywać pośrednie wyniki przemiennika po zastosowaniu filtrów, np.

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

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

Wyrażenie alias będzie zapobiec wielu kwestii wykonania filtra.

Mam nadzieję, że to pomoże.


4
Czy to oznacza, że ​​filtr jest wykonywany dwukrotnie?
Błysk

9
Tak, jest wykonywany dwukrotnie.
nathancahill

11
upewnij się, że przeczytałeś odpowiedź @Wumms, zanim zdecydujesz się użyć tego (a nie będziesz) ...
epeleg

1
Nieważne, widzę, że odpowiedź nie zawierała części o wyrażeniu aliasu, kiedy skomentowałeś.
Adam Goodwin,

2
Ta odpowiedź obsługuje wiele wyrażeń filtrów, w przeciwieństwie do bieżącej najwyższej odpowiedzi. ie){{(data|filter:query|filter:query2).length}}
czakeda

45

Najłatwiejszy sposób, jeśli masz

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

Filtrowana długość danych

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

Jest to najbardziej przydatne dla każdego, kto używa dyrektywy dir-paginate dla narzędzi kątowych, ponieważ aliasing i alternatywa dla wersji wcześniejszej niż 1.3 nie są obsługiwane.
pcnate

Czy to wyliczy dane dwukrotnie?
Jeppe,

36

ngRepeat tworzy kopię tablicy po zastosowaniu filtru, więc nie można używać tablicy źródłowej do odwoływania się tylko do przefiltrowanych elementów.

W twoim przypadku może być lepiej zastosować filtr wewnątrz kontrolera za pomocą $filterusługi:

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

  $scope.filteredData = myNormalData;

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

  // ...
}

I filteredDatazamiast tego używasz właściwości w swoim widoku. Oto działający Plunker: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview


1
Zrozumiałem, że używam {{filteredData.length}}zamiast data.length. Zrozumiałem również, że myInputModeljest to model odwzorowany na zapytanie wejściowe, które filtruje dane. valbyłby tekst wpisany w danych wejściowych (w zasadzie zapytanie), ale za każdym razem, gdy piszę, zmienia się. Ale co filterFiltertu jest ? Mogę dodać, że utworzyłem własny filtr niestandardowy (w którym mogę określić klucz obiektu, który należy rozważyć do filtrowania).
user109187

Zgadza się. Użyj również, ng-repeat="person in filteredData"ponieważ nie ma sensu filtrować go dwukrotnie. Z $filterusługi można poprosić o określonej przez filtr tylko przyrostka go z „Filtr”, np: dateFilter, jsonFilter, itd. Jeśli używasz swój własny filtr, wystarczy użyć tamten zamiast rodzajowy filterFilter.
Josh David Miller,

Co powiesz na zastosowanie wielu filtrów do jednego powtórzenia ng, powiedzmy, że masz 2 listy rozwijane z wartościami i jedno pole wprowadzania tekstu?
alchemikacja

Filtr jest tylko funkcją, więc wystarczy przekazać wynik pierwszego filtra do drugiego.
Josh David Miller

29

Od AngularJS 1.3 możesz używać aliasów:

item in items | filter:x as results

i gdzieś:

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

Z dokumentów :

Możesz także podać opcjonalne wyrażenie aliasowe, które będzie przechowywać pośrednie wyniki przemiennika po zastosowaniu filtrów. Zwykle służy to do renderowania specjalnego komunikatu, gdy filtr jest aktywny w repeaterze, ale zestaw wyników filtrowania jest pusty.

Na przykład: item in items | filter: x as wyniki będą przechowywać fragment powtarzanych elementów jako wyniki, ale dopiero po przetworzeniu elementów przez filtr.


Nie mogę zastosować się $scope.$watchdo tego aliasu wyniku. Jakieś wskazówki dotyczące $broadcastwprowadzania resultszmiennej aliasu ?
DeBraid

25

Warto również zauważyć, że można przechowywać wiele poziomów wyników, grupując filtry

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>

oto skrzypka demonstracyjna


13

Oto działający przykład Zobacz na 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
Problem z tym podejściem polega na tym, że filtr jest uruchamiany dwa razy: raz w ngRepeat i raz w kontrolerze.
Josh David Miller

Tak, masz rację, czy możesz zamieścić swój działający przykład na podstawie swojej odpowiedzi, chciałbym nauczyć się nieco więcej filtrów? Dzięki.
Maksym

2
Pewnie. Oto działający Plunker: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview . Właśnie edytowałem twoje.
Josh David Miller,

10

Możesz to zrobić na 2 sposoby . W szablonie iw kontrolerze . W szablonie możesz ustawić filtrowaną tablicę na inną zmienną, a następnie użyć jej tak, jak chcesz. Oto jak to zrobić:

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

Jeśli potrzebujesz przykładów, zapoznaj się z filtrowanymi przykładami / pokazami AngularJs

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.