AngularJS: Directivas y Filtros

Logo de AngularJS

En esta serie de posts estoy haciendo un repaso de muchas de las características de angularjs. En el primer post explicaba los conceptos básicos en que se fundamenta angular, y especialmente la capa de presentación, mientras que en el segundo profundizaba un poco en la organización interna basada en módulos, servicios e inyección de dependencias.

Esta vez toca volver a la capa de presentación para hacer hincapié en dos herramientas que ofrece angular para desarrollar la capa de presentación de forma lógica y sencilla.

OJO: en estos post no vas a encontrar información detallada sobre cómo trabajar con angular ni mucho código fuente, si estás buscando ese tipo de detalles, te recomiendo que eches un vistazo a la documentación oficial o sigas el tutorial. Si quieres profundizar en el tema, AngularJS: Up and Running me pareció un buen libro y tengo buenas referencias del curso de AngularJS que ofrecen Pedro Hurtado y Xavier Cerdá.

Directivas

En el primer post expliqué que angular utiliza un sistema de databinding declarativo bidireccional para enganchar el $scope, es decir el ViewModel en terminología de angular, con la vista. Para ello se emplean lo que en angular se conoce como directivas.

Las directivas tienen el aspecto de elementos o atributos en el código HTML, pero son interpretadas por angular al generar las vistas, lo que nos permite modificar el DOM o añadir nuevos comportamientos.

Podéis ver bastantes ejemplos de directivas en el proyecto UI Boostrap, que permite utilizar los componentes de Twitter Bootstrap en angular, pero para hacernos una idea de cómo funcionan vamos a ver un par de ejemplos.

Una directiva de atributo se utiliza como si fuese un atributo más de un elemento HTML y puede llevar parámetros o no, pero además tiene la ventaja de que desde ella podemos referenciar el $scope (el ViewModel) para realizar acciones o leer datos:

<div ng-controller="SampleController">
  <input ng-model="person.name"/>
  <button ng-click="save()"/>
</div>

En este ejemplo aparecen las directivas ng-controller, ng-model y ng-click, que nos permiten enlazar un Controller a un elemento HTML, enlazar la propiedad person.model a un cuadro de texto e invocar la función $scope.save() al pulsar un botón.

Las directivas de elemento se utilizan como cualquier otro elemento HTML y simplifican los procesos de creación de fragmentos HTML. Por ejemplo, podemos tener una directiva que nos permita generar pestañas:

<tabs>
  <pane heading="Static title">Static content</pane>
  <pane ng-repeat="pane in panes" 
        heading="{{pane.title}}" 
        active="pane.active">
    {{pane.content}}
  </pane>
</tabs>

Aquí estamos usando las directivas tabs y pane para generar la estructura de HTML necesaria para implementar un sistema de pestañas.

Lo mejor de las directivas es que es muy sencillo crear nuevas directivas para encapsular pequeños fragmentos de funcionalidad y poder así mantener unas vistas más limpias y claras. Podríamos considerar las directivas como algo similar a los controles de usuario de ASP.NET o los HTML helpers de ASP.NET MVC.

Filtros

Los filtros en angular son los encargados de procesar la información antes de mostrarla en pantalla. Permiten hacer muchas cosas, pero lo más habitual es utilizarlos para modificar los valores a presentar o aplicarles formato.

Se aplican dentro de las expresiones de databinding y se indican con el caracter |. Al igual que las directivas, los filtros pueden recibir parametros que modifiquen su comportamiento.

El ejemplo más típico de uso de un filtro que modifica lo que estamos presentando es el filtro filter que permite seleccionar elementos de un array:

<ul>
  <li ng-repeat="c in customers | filter:{region: 'Madrid'}">{{c.name}}</li>
</ul>

En este ejemplo estaríamos filtrando los elementos del array customers antes de pasárselos a la directiva ng-repeat para mostrar sólo los clientes cuya region es Madrid.

En el caso de formatear valores, podríamos tener un filtro que tradujese cadenas de texto antes de mostrarlas al usuario y su uso sería similar a este:

<p>{{'SAMPLE_KEY' | localize}}</p>

El filtro localize se encargaría de traducir, seguramente usando algún servicio, la expresión a la que se aplica el filtro, en este caso 'SAMPLE_KEY'.

Al igual que las directivas, es fácil definir nuevos filtros que permitan reutilizar comportamiento entre distintas partes de la aplicación. Además, angular permite aplicar secuencialmente filtros, por lo que es sencillo crear muchos filtros focalizados y luego componerlos para obtener el resultado final:

<p>{{message | pluralize | toUpperCase}}</p>

Seguramente lo más confuso de los filtros es que el primer ejemplo que se ve es el de filtro filter, por lo que parece que únicamente sirven para filtrar colecciones, pero en realidad, como hemos visto pueden utilizarse para otro tipo de cosas, como formatear valores o incluso realizar otras transformaciones (por ejemplo, agregados sobre colecciones).

Resumen

Los filtros y las directivas son de las cosas que más me gustan de angular. En la mayoría de aplicaciones el código más feo, más enrevesado y más difícil de mantener está en la capa de presentación y, sobre todo, en las vistas, por lo que contar con herramientas como estas es de mucha ayuda para que la aplicación no se haga inmanejable con el paso del tiempo.

Todavía no he dicho nada en esta serie sobre otro factor que está bastante bien trabajado en angular, que son las herramientas para realizar tests, pero eso queda para el próximo post.