> Manuales > Manual de AngularJS

Usos más detallados de la directiva ngRepeat para filtrar, ordenar los elementos y acceder a variables embutidas que nos dan información sobre las repeticiones.

La directiva ngRepeat de AngularJS es una de esas cosas que llaman la atención, por la sencillez y rapidez con la que se puede implementar un bucle que nos repite una plantilla HTML, pero sobre todo por su potencia.

La directiva ya la hemos usado en diversos ejemplos anteriormente, incluso tenemos un artículo anterior donde se introdujeron algunos detalles básicos de ng-repeat para empezar a usarla. Ahora queremos profundizar un poco más en otros usos que resultarán muy útiles para cualquier tipo de aplicación web.

En la documentación de la directiva ngRepeat encuentras muchos datos útiles, aqui te vamos a resumir algunos y vamos a realizar un ejemplo que lo ponga todo en práctica.

Sintaxis ngRepeat

Nos tenemos que familiarizar primero con la sintaxis usada para especificar el comportamiento del bucle en ngRepeat. Aunque ya lo hemos visto en cantidad de ejemplos, comencemos por repasar la sintaxis básica.

<p ng-repeat="elem in elementos">
  {{ elem }}
</p>

En la directiva indicamos el recorrido a una colección y la variable donde vamos a tener el elemento actual: "elem in elementos". En este caso "elementos" es la colección que vamos a recorrer en el bucle y "elem" es la variable donde vamos a tener el elemento actual en cada repetición.

Pero eso no es lo único que se puede marcar en esta directiva, también podremos especificar otras cosas, colocando el caracter "|" (tubería / pipe) como separador.

ng-repeat="elem in elementos | filtros | ordenacion"

Técnicamente podemos decir que dentro del HTML de tu repetición tendrás un scope local, donde encontrarás el elemento actual sobre el que estás iterando, así como otras variables útiles que veremos también, como $index que nos devuelve el índice actual en el recorrido.

Filtrado en ngRepeat

El filtrado nos sirve para hacer una búsqueda dentro de los elementos de la colección que tenemos en un array o en un objeto en nuestro modelo.

Nota: Por supuesto, la colección está del lado del cliente completa y lo que hace el filter es simplemente definir cuáles elementos de esa colección desean visualizarse en la repetición. Osea, es un filtrado de datos de los que ya disponemos, no un buscador que pueda buscar entre miles de elementos y solo recibir unos pocos en el cliente. Cuando estás filtrando ya tienes esos elementos en la memoria de Javascript en un array u objeto.

Se indica con la palabra filter, seguida por ":" y la cadena o variable donde está la cadena que nos sirve para filtrar.

ng-repeat="cerveza in vm.cervezas | filter:'pale' "

Esto nos mostrará solo aquellas cervezas que tienen la palabra "pale" escrita por algún lado. Por supuesto, en lugar de un literal de cadena para el filtrado, puedes usar una variable de tu modelo.

ng-repeat="cerveza in vm.cervezas | filter:vm.filtroCliente"

Ahora utilizarás el contenido de la variable vm.filtroCliente para mostrar aquellos elementos que corresponda.

Orden de los elementos en la repetición

Ahora veamos cómo expresar el orden de visualización de los elementos en la repetición. Para ello usamos la palabra "ordenBy", seguido de ":" y el campo sobre el que se debe ordenar. Opcionalmente colocamos después si el orden es ascendente o descendente.

ng-repeat="cerveza in vm.cervezas | orderBy:'name':true"

En este caso ordenamos los elementos por el campo "name". Lógicamente debe de ser un atributo del objeto que estás recorriendo en la colección. Luego opcionalmente colocamos un boleano para indicar el orden. De manera predeterminada el orden es ascendente. Si el boleano es true, entonces el orden se hace descendente y si es false, entonces es ascendente.

Nuevamente, el orden se indicará habitualmente a partir de variables de Javascript o del modelo de nuestra vista. En un código que podría ser como este:

ng-repeat="cerveza in vm.cervezas | orderBy:vm.campo:vm.orden"

Variables de la repetición en el scope local

Como hemos dicho existe un scope local que nos expone el elemento actual de nuestra repetición. Pero además tenemos una serie de variables que AngularJS nos ofrece de manera adicional. Son variables que resultarán muy útiles para tus necesidades habituales en recorridos.

Por ejemplo en el scope actual tenemos la variable $index, que nos indica el índice actual en la iteración. El primer índice recuerda que es cero, el segundo será uno, etc. Para mostrar ese índice hacemos como con cualquier otro dato que exista en el scope, meterlo dentro de una expresión encerrada con dobles llaves.

<p ng-repeat="elem in elementos">
  El elemento actual es {{ $index }} y su valor es {{ elem }}
</p>

Junto con el $index, este es el conjunto de variables inyectadas automáticamente en el scope local:

Ejercicio de repetición con ng-repeat con filtrado, orden y variables de scope local

Ahora vamos a ver el código de un ejercicio que nos facilite practicar con estos sistemas para personalizar la repetición de un template en AngularJS.

El ejemplo es parecido al ejercicio anterior donde conocimos JSONP en AngularJS, solo que ahora aplicamos las posibilidades de ngRepeat vistas en este artículo. Para ello hemos incorporado un par de controles especiales, que nos permiten:

<div ng-app="apiApp" ng-controller="apiAppCtrl as vm">
  <h1>Pruebo Ajax con JSONP</h1>
  <p>
      Busca cerveza:
      <input type="text" ng-model="vm.nombre"> <input type="button" value="Buscar" ng-click="vm.buscaCervezas()">
  </p>
  <aside>
       <h2>Filtra:</h2>
        <input type="text" ng-model="vm.filtroCliente">
       <h2>Orden</h2>
        <p>
            <button ng-click="vm.orden=false">Alfabetico</button>
            <br />
            <button ng-click="vm.orden=true">Contrario</button>
        </p>
        <p>
            <input type="radio" name="campo" ng-model="vm.campo" value="name"> Nombre
            <br />
            <input type="radio" name="campo" ng-model="vm.campo" value="description"> Descripción
        </p>
  </aside>
  <section>
    <ul>
      <li ng-repeat="cerveza in vm.cervezas | filter:vm.filtroCliente | orderBy:vm.campo:vm.orden" ng-class="{even: $even, odd: $odd}">
        <span>{{$index +1}}.- {{cerveza.name}},</span> {{ cerveza.description }}
      </li>
    </ul>
  </section> 
</div>

Para el texto del filtrado usamos el INPUT type text que hemos marcado con ng-model="vm.filtroCliente".

Para el orden tenemos dos tipos de controles, diferentes para poder practicar con más cosas. Tenemos un par de botones que nos permiten marcar orden alfabético o contrario, que tienen sus correspondientes ng-click para definir comportamientos. Por otra parte tenemos un par de campos INPUT de radio para definir si queremos que se ordene por el nombre de la cerveza o su campo descripción.

Pero sobre todo te tienes que fijar en el listado de cervezas que realizamos con una lista UL y sus correspondientes LI. Echa un vistazo a la directiva y al template que engloba:

<li ng-repeat="cerveza in vm.cervezas | filter:vm.filtroCliente | orderBy:vm.campo:vm.orden" ng-class="{even: $even, odd: $odd}">
<span>{{$index +1}}.- {{cerveza.name}},</span> {{ cerveza.description }}
</li>

Aquí tenemos varios elementos que destacar:

El Javascript tendrá una pinta como la siguiente:

angular
    .module('apiApp', [])
    .controller('apiAppCtrl', controladorPrincipal);

function controladorPrincipal($scope, $http){
    var vm=this;

    vm.orden = false;
    vm.campo = "name";
    
    var url = "http://api.openbeerdatabase.com/v1/beers.json?callback=JSON_CALLBACK";
    if(vm.nombre){
        url += "&query=" + vm.nombre
    }
    vm.buscaCervezas = function(){
        $http.jsonp(url).success(function(respuesta){
            console.log("res:", respuesta);
            vm.cervezas = respuesta.beers;
        });
    }
}

Realmente en este Javascript hay poco que necesites aprender, que no hayas visto ya en artículos anteriores. Te podrá interesar la inicialización de datos en el scope qe encuentras en las primeras líneas de la función del controlador.

Aunque para la materia que nos trata no importa demasiado, sí que necesitarás unos estilos CSS para formatear un poco la presentación de ese HTML, de manera que quede bonito y puedas apreciar algunas cosas como los colores de fondo de tipo cebra para los elementos de la lista.

body{ font-family: sans-serif;}
li{
    font-size: 0.8em;
    margin-bottom: 10px;
    padding: 10px;
}
li span{
    font-weight: bold;
    display: block;
    font-size: 1.2em;
}
aside{
    width: 200px;
    float: right;
    padding: 20px;
    display: table-cell;
}
aside h2{
    margin-bottom: 3px;
}
section{
    display: table-cell;
}
li.even{
    background-color: #d5d5d5;
}
li.odd{
    background-color: #d5d5ff;   
}

Eso es todo de momento, espero que puedas aprovechar ya mismo algunas de estas potentes características de ngRepeat. Como habrás encontrado, esta directiva permite hacer cosas impactantes sin escribir nada de código, algo que apreciarás sobre todo si tienes algo de experiencia en Javascript o librerías como jQuery. Pero OJO, esa misma potencia puede que resulte perjudicial para tu aplicación si se usa sin control, nunca intentes usar ng-repeat con conjuntos masivos de datos, a lo sumo con elementos de 100 en 100, aplicando técnicas como la paginación para reducir los elementos en la vista.

Alberto Basalo

Alberto Basalo es experto en Angular y otras tecnologías basadas en Javascript,...

Manual