Cómo mostrar la longitud de los datos filtrados ng-repeat


438

Tengo una matriz de datos que contiene muchos objetos (formato JSON). Se puede suponer lo siguiente como contenido de esta matriz:

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

Ahora, muestro estos detalles como:

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

Aquí, la consulta se modela en un campo de entrada en el que el usuario puede restringir los datos que se muestran.

Ahora, tengo otra ubicación en la que visualizo el recuento actual de personas / personas que se muestran, es decir Showing {{data.length}} Persons

Lo que quiero hacer es que cuando el usuario busca a una persona y los datos que se muestran se filtran en función de la consulta, Showing...personstambién cambia el valor de las personas que se muestran actualmente. Pero no está sucediendo. Siempre muestra el total de personas en los datos en lugar del filtrado: ¿cómo obtengo el recuento de datos filtrados?

Respuestas:


746

Para Angular 1.3+ (créditos a @Tom)

Use una expresión de alias (Docs: Angular 1.3.0: ngRepeat , desplácese hacia abajo hasta la sección Argumentos ):

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

Para angular anterior a 1.3

Asigne los resultados a una nueva variable (por ejemplo filtered) y acceda a ella:

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

Mostrar el número de resultados:

Showing {{filtered.length}} Persons

Violín un ejemplo similar . Los créditos van a Pawel Kozlowski


42
Esta es la respuesta simple que no repite la ejecución del filtro.
agmin

3
@Ben: sí. Puede acceder desde el controlador usando $scope.filtered.length.
Wumms

2
Eso no me funciona. Registros undefined, probablemente porque al momento de registrarlo, la variable aún no está definida. Entonces, ¿cómo podría asegurarme de que el código en el controlador se ejecuta después de que se definió la variable y se aplicó el filtro en la vista?
Ben

66
@Ben: Supongo que esto está fuera de tema. Consideraría crear un filtro personalizado, por ejemplo , jsfiddle , sin embargo, también podría verlo dentro del controlador:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms

3
La versión 1.3+ no funciona si quería añadir LimitTo: person in data | filter:query as filtered | limitTo:5. Así que tuve que usar la versión anterior a la 1.3:person in filtered = (data | filter: query) | limitTo: 5
benjovanic

333

Para completar, además de las respuestas anteriores (realizar el cálculo de personas visibles dentro del controlador) también puede realizar esos cálculos en su plantilla HTML como en el ejemplo a continuación.

Suponiendo que su lista de personas está en datavariable y que filtra personas usando el querymodelo, el siguiente código funcionará para usted:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - imprime el número total de personas
  • {{(data|filter:query).length}} - imprime el número filtrado de personas

Tenga en cuenta que esta solución funciona bien si desea utilizar datos filtrados solo una vez en una página. Sin embargo, si usa datos filtrados más de una vez, por ejemplo, para presentar elementos y mostrar la longitud de la lista filtrada, sugeriría usar una expresión de alias (descrita a continuación) para AngularJS 1.3+ o la solución propuesta por @Wumms para la versión de AngularJS anterior a 1.3.

Nueva característica en Angular 1.3

Los creadores de AngularJS también notaron ese problema y en la versión 1.3 (beta 17) agregaron la expresión "alias" que almacenará los resultados intermedios del repetidor después de que se hayan aplicado los filtros, por ejemplo

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

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

La expresión de alias evitará un problema de ejecución de múltiples filtros.

Espero que le ayudará.


44
¿Significará esto que el filtro se ejecuta dos veces?
Flash

99
Sí, se ejecuta dos veces.
nathancahill

11
asegúrese de leer la respuesta @Wumms antes de decidirse a utilizar este (y no lo hará) ...
epeleg

1
No importa, veo que la respuesta no contenía la parte sobre la expresión de alias cuando hiciste tu comentario.
Adam Goodwin

2
Esta respuesta admite múltiples expresiones de filtro a diferencia de la respuesta principal actual. es decir){{(data|filter:query|filter:query2).length}}
chakeda

45

La forma más fácil si tienes

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

Longitud de datos filtrados

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

Esto es más útil para cualquiera que use la directiva angular utils dir-paginate, ya que el aliasing y la alternativa pre ng-1.3 no son compatibles.
pcnate

¿Esto enumerará los datos dos veces?
Jeppe

36

ngRepeat crea una copia de la matriz cuando aplica un filtro, por lo que no puede usar la matriz fuente para hacer referencia solo a los elementos filtrados.

En su caso, puede ser mejor aplicar el filtro dentro de su controlador utilizando el $filterservicio:

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

  $scope.filteredData = myNormalData;

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

  // ...
}

Y luego usa la filteredDatapropiedad en su vista en su lugar. Aquí hay un Plunker en funcionamiento: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview


1
Lo que entendí es que uso en {{filteredData.length}}lugar de data.length. También entendí quemyInputModel es el modelo asignado a la consulta de entrada que filtra los datos. valsería el texto que se escribe en la entrada (básicamente consulta) pero cada vez que escribo, cambia. Pero que hay filterFilteraqui? Podría agregar que tengo mi propio CustomFilter creado (en el que puedo especificar qué clave del objeto considerar para el filtrado).
user109187

Así es. También utilícelo ng-repeat="person in filteredData"ya que no tiene sentido filtrarlo dos veces. Con el $filterservicio, puede solicitar un filtro específico simplemente con el sufijo "Filtro", por ejemplo:dateFilter , jsonFilter, etc Si usted está utilizando su propio filtro personalizado, sólo tiene que utilizar uno que en lugar del genérico filterFilter.
Josh David Miller

¿Qué pasa con la aplicación de múltiples filtros a una repetición ng, digamos que tiene 2 menús desplegables con valores y un campo de entrada de texto?
alquimia

El filtro es solo una función, por lo que simplemente pasaría la salida del primer filtro al segundo filtro.
Josh David Miller

29

Desde AngularJS 1.3 puede usar alias:

item in items | filter:x as results

y en alguna parte:

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

De documentos :

También puede proporcionar una expresión de alias opcional que luego almacenará los resultados intermedios del repetidor después de que se hayan aplicado los filtros. Por lo general, esto se usa para representar un mensaje especial cuando un filtro está activo en el repetidor, pero el conjunto de resultados filtrado está vacío.

Por ejemplo: artículo en artículos | filter: x como resultados almacenará el fragmento de los elementos repetidos como resultados, pero solo después de que los elementos hayan sido procesados ​​a través del filtro.


No puedo aplicar $scope.$watcha este resultado con alias. ¿Algún consejo para $broadcastla resultsvariable con alias ?
DeBraid

25

También es útil tener en cuenta que puede almacenar múltiples niveles de resultados agrupando filtros

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>

aquí hay un violín de demostración


13

Aquí está el ejemplo trabajado Ver en 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;
  });
});


44
El problema con este enfoque es que está ejecutando el filtro dos veces: una en ngRepeat y otra en el controlador.
Josh David Miller

Sí, tienes razón, ¿puedes publicar tu ejemplo de trabajo basado en tu respuesta, me gustaría aprender un poco más de filtros? Gracias.
Maksym

2
Por supuesto. Aquí está el Plunker de trabajo: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview . Acabo de editar el tuyo.
Josh David Miller

10

Puedes hacerlo de 2 maneras . En plantilla y en controlador . En la plantilla, puede establecer su matriz filtrada en otra variable y luego usarla como desee. Aquí está cómo hacerlo:

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

Si necesita ejemplos, vea los ejemplos / demostraciones de conteo filtrado de AngularJs

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.