Как отобразить длину отфильтрованных данных ng-repeat

406

У меня есть массив данных, который содержит много объектов (формат 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 также изменяет значение отображаемых в настоящее время людей. Но этого не происходит. Он всегда отображает полных лиц в данных, а не отфильтрованных - как я могу получить количество отфильтрованных данных?

Теги:

8 ответов

676

Для Angular 1,3 + (кредиты @Tom)

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

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

Для Angular до 1.3

Назначьте результаты новой переменной (например, filtered) и получите доступ к ней:

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

Отобразить количество результатов:

Showing {{filtered.length}} Persons

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

  • 41
    Это простой ответ, который не повторяет выполнение фильтра.
  • 1
    Что если мне теперь нужно получить доступ к значению filtered.length внутри моего контроллера? Есть ли способ сделать это?
Показать ещё 17 комментариев
297

Для полноты, в дополнение к предыдущим ответам (выполнить расчет видимых людей внутри контроллера), вы также можете выполнить эти вычисления в своем 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}} - печатает отфильтрованное количество людей

Примечание, что это решение отлично работает, если вы хотите использовать отфильтрованные данные только один раз на странице. Однако, если вы используете отфильтрованные данные более одного раза, например. для представления элементов и отображения длины отфильтрованного списка я бы предложил использовать выражение alias (описано ниже) для AngularJS 1.3 + или решение, предложенное @Wumms для версии AngularJS ранее до 1.3.

Новая функция в Angular 1.3

Создатели AngularJS также заметили эту проблему и в версии 1.3 (beta 17) добавили выражение "псевдоним", которое будет хранить промежуточные результаты ретранслятора после того, как фильтры были применены, например
<div ng-repeat="person in data | filter:query as results">
    <!-- template ... -->
</div>

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

выражение псевдонима предотвратит проблему с несколькими фильтрами.

Я надеюсь, что это поможет.

  • 4
    Означает ли это, что фильтр выполняется дважды?
  • 9
    Да, это выполняется дважды.
Показать ещё 10 комментариев
31

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
    Что я понял, так это то, что вместо data.length я использую {{filteredData.length}} data.length {{filteredData.length}} . Я также понял, что myInputModel - это модель, сопоставленная с входным запросом, который фильтрует данные. val будет текстом, который вводится во ввод (в основном запрос), но каждый раз, когда я печатаю, он меняется. Но что здесь за filterFilter ? Я мог бы добавить, что у меня есть свой собственный customFilter (в котором я могу указать, какой ключ объекта следует учитывать при фильтрации).
  • 0
    Вот так. Также просто используйте ng-repeat="person in filteredData" как нет смысла фильтровать его дважды. С помощью службы $filter вы можете запросить определенный фильтр, просто добавив к нему суффикс «Filter», например: dateFilter , jsonFilter и т. Д. Если вы используете свой собственный фильтр, просто используйте его вместо универсального filterFilter .
Показать ещё 2 комментария
28

Так как AngularJS 1.3 вы можете использовать псевдонимы:

item in items | filter:x as results

и где-нибудь:

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

От docs:

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

Например: элемент в элементах | фильтр: x, поскольку результаты сохранят фрагмент повторяющихся элементов в качестве результатов, но только после элементов были обработаны через фильтр.

  • 0
    Я не могу применить $scope.$watch к этому псевдониму. Какие-нибудь советы для $broadcast псевдонимов results ?
23

Также полезно отметить, что вы можете хранить несколько уровней результатов, группируя фильтры

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>

здесь демонстрационная скрипка

20

Самый простой способ, если у вас

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

Отфильтрованная длина данных

<div>{{ (data | filter: query).length }}</div>
  • 0
    Это наиболее полезно для любого, кто использует угловую директиву утилит dir-paginate, поскольку псевдонимы и альтернатива pre ng-1.3 не поддерживаются.
  • 0
    Будет ли это перечислять данные дважды?
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 и один раз в контроллере.
  • 0
    Да, вы правы, можете ли вы опубликовать свой рабочий пример на основе вашего ответа, я хотел бы узнать немного больше фильтров? Благодарю.
Показать ещё 1 комментарий
6

Вы можете сделать это с помощью 2 способа. В шаблоне и в Контроллере. В шаблоне вы можете настроить фильтрованный массив на другую переменную, а затем использовать его так, как хотите. Вот как это сделать:

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

Если вам нужны примеры, см. Примеры/демонстрационные примеры фильтров AngularJs

Ещё вопросы

Сообщество Overcoder
Наверх
Меню