Як відобразити довжину відфільтрованих даних ng-повторів


438

У мене є масив даних, який містить багато об'єктів (формат JSON). В якості вмісту цього масиву можна вважати наступне:

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

Тепер я показую ці деталі як:

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

Тут запит моделюється до поля введення, в якому користувач може обмежувати відображені дані.

Тепер у мене є ще одне місце, в якому я відображаю поточну кількість людей / людей, які відображаються, тобто Showing {{data.length}} Persons

Що я хочу зробити, це те, що коли користувач здійснює пошук людини, а відображені дані фільтруються на основі запиту, Showing...personsтакож змінюється значення людей, що відображаються в даний час. Але це не відбувається. Він завжди відображає загальну кількість людей у ​​даних, а не відфільтрованих - як я можу отримати кількість відфільтрованих даних?

Відповіді:


746

Для кутових 1.3+ (кредити до @Tom)

Використовуйте вираз псевдоніму (Docs: Angular 1.3.0: ngRepeat , прокрутіть вниз до розділу Аргументи ):

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

Для кутових до 1,3

Призначте результати новій змінній (наприклад filtered) та отримайте доступ до неї:

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

Показати кількість результатів:

Showing {{filtered.length}} Persons

Візьміть подібний приклад . Кредити йдуть до Павла Козловського


42
Це проста відповідь, яка не повторює виконання фільтра.
agmin

3
@Ben: Так. Ви можете отримати доступ до нього всередині контролера за допомогою $scope.filtered.length.
Wumms

2
Це не працює для мене. Журнали undefined, ймовірно, тому що під час реєстрації в ньому змінна ще не визначена. Тож як би я забезпечив запуск коду в контролері після визначення змінної та застосування фільтра у поданні?
Бен-

6
@Ben: Гадаю, це йде поза темою. Я б розглядав можливість створити спеціальний фільтр, наприклад, jsfiddle , однак ви можете також переглянути його всередині контролера:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms

3
Версія 1.3+ не працювала, якщо я хотів додати limitTo : person in data | filter:query as filtered | limitTo:5. Тож мені довелося скористатися до 1.3 версії:person in filtered = (data | filter: query) | limitTo: 5
benjovanic

332

Для повноти, крім попередніх відповідей (виконайте обчислення видимих ​​людей всередині контролера), ви також можете виконати такі обчислення у вашому HTML-шаблоні, як у наведеному нижче прикладі.

Якщо припустити, що ваш список людей є dataзмінним і ви фільтруєте людей за queryмоделлю, наступний код буде працювати для вас:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - друкує загальну кількість людей
  • {{(data|filter:query).length}} - відбитки відфільтрованої кількості людей

Зауважте, що це рішення працює добре, якщо ви хочете використовувати відфільтровані дані лише один раз на сторінці. Однак якщо ви використовуєте відфільтровані дані не один раз, наприклад, для представлення елементів та показу довжини відфільтрованого списку, я б запропонував використовувати псевдонім вираз (описаний нижче) для AngularJS 1.3+ або рішення, запропоноване @Wumms для версії AngularJS до 1.3.

Нова особливість у кутовій 1.3

Творці AngularJS також помітили цю проблему, і у версії 1.3 (бета-версія 17) вони додали вираз "псевдонім", який зберігатиме проміжні результати ретранслятора після застосування фільтрів, наприклад

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

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

вираз псевдоніма дозволить запобігти багаторазовий питання виконання фільтра.

Я сподіваюся, що це допоможе.


4
Чи означає це, що фільтр виконується двічі?
Спалах

9
Так, він виконується двічі.
nathancahill

11
переконайтеся, що ви прочитали відповідь @Wumms, перш ніж ви вирішите скористатися цією (і не будете) ...
epeleg

1
Незважаючи на те, я бачу, що відповідь не містила частини про вираз псевдоніма, коли ви робили коментар.
Адам Гудвін

2
Ця відповідь підтримує декілька виразів фільтрів на відміну від поточної верхньої відповіді. тобто){{(data|filter:query|filter:query2).length}}
chakeda

45

Найпростіший спосіб, якщо у вас є

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

Відфільтрована довжина даних

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

Це найкорисніше для всіх, хто використовує директиву углових утилітів dir-paginate, оскільки псевдонім та альтернатива pre ng-1.3 не підтримуються.
pcnate

Чи буде це перераховано дані двічі?
Jeppe

36

ngRepeat створює копію масиву, коли застосовує фільтр, тому ви не можете використовувати вихідний масив для посилання лише на відфільтровані елементи.

У вашому випадку, можливо, буде краще застосувати фільтр всередині вашого контролера за допомогою $filterпослуги:

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

  $scope.filteredData = myNormalData;

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

  // ...
}

А потім ви використовуєте filteredDataвластивість у своєму перегляді замість цього. Ось робочий Plunker: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview


1
Я зрозумів, що я використовую {{filteredData.length}}замість цього data.length. Я також зрозумів, що myInputModelце модель, відображена на вхідний запит, який фільтрує дані. valце текст, який набирається на вході (в основному запит), але щоразу, коли я вводя, він змінюється. Але що filterFilterтут? Я можу додати, що у мене створений власний customFilter (в якому я можу вказати, який ключ об'єкта слід врахувати для фільтрації).
користувач109187

Це вірно. Також просто використовуйте, ng-repeat="person in filteredData"оскільки немає сенсу фільтрувати його двічі. З $filterобслуговуванням, ви можете задати для конкретного фільтра, просто суфікса його «Фільтр», наприклад: dateFilter, jsonFilterі т.д. Якщо ви використовуєте свій власний фільтр, просто використовуйте один замість родового filterFilter.
Джош Девід Міллер

А як із застосуванням декількох фільтрів до одного ng-повтору, скажімо, у вас є 2 спадні місця зі значеннями та одне поле введення тексту?
алкоголіка

Фільтр - це лише функція, тому ви просто передасте вихід першого фільтра другому.
Джош Девід Міллер

29

Оскільки AngularJS 1.3 ви можете використовувати псевдоніми:

item in items | filter:x as results

і десь:

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

З документів :

Ви також можете надати додатковий вираз псевдоніму, який буде зберігати проміжні результати ретранслятора після застосування фільтрів. Зазвичай це використовується для подання спеціального повідомлення, коли на ретрансляторі активний фільтр, але відфільтрований набір результатів порожній.

Наприклад: пункт у пунктах | filter: x як результати зберігатиме фрагмент повторних елементів як результати, але лише після того, як елементи будуть оброблені через фільтр.


Я не в змозі застосувати $scope.$watchцей відчужений результат. Будь-які поради щодо $broadcastінжиніальної resultsзмінної?
DeBraid

25

Також корисно зазначити, що ви можете зберігати кілька рівнів результатів, групуючи фільтри

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>

ось демо-скрипка


13

Ось опрацьований приклад Дивіться на 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
Проблема такого підходу полягає в тому, що ви двічі запускаєте фільтр: один раз у ngRepeat і один раз у контролері.
Джош Девід Міллер

Так, ви маєте рацію, чи можете ви розмістити свій робочий приклад на основі вашої відповіді, я хотів би дізнатися трохи більше фільтрів? Дякую.
Максим

2
Звичайно. Ось робочий Plunker: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview . Я щойно відредагував твій.
Джош Девід Міллер

10

Зробити це можна двома способами . У шаблоні та в контролері . У шаблоні ви можете встановити свій відфільтрований масив на іншу змінну, а потім використовувати його як хочете. Ось як це зробити:

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

Якщо вам потрібні приклади, дивіться приклади / демонстрації підрахунків відфільтрованих AngularJs

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.