Introducción a las directivas

Las directivas en Angular son unas instrucciones que nos permiten ampliar las funcionalidades de las vistas. Es algo parecido (salvando las diferecias, claro), a lo que hacer el motor de plantillas Twig aunque, al contrario que este, el uso de directivas en Angular solo es operativo en el contexto de Angular.

Las directivas nos permiten, por ejemplo, incorporar condicionales y bucles en nuestras vistas, como vamos a ver en este artículo. Además, ciertos elementos que pudieran parecer etiquetas «especiales» o algún tipo de instrucción (como es el caso de <router-outlet></router-outlet>) son consideradas también directivas en Angular.

En este artículo, veremos como usar esas directivas (en combinación con un poquito de JavaScript) para mejorar lo que estamos haciendo para ver la lista de clientes, y los datos de los mismos.

LO QUE VAMOS A HACER

Vamos a modificar el listado de clientes (CustomersListComponent) y la vista de la ficha de un cliente (CustomerDataComponent) aprovechando lo que nos aportan las directivas de las vistas de Angular. Ahora mismo tenemos dos carencias muy importantes:

  • Por un lado, la lista de clientes está grabada «a fuego» en la vista del componente (customers-list.component.html). Esto nos ha valido para aprender sobre los enlaces con paso de parámetros, pero, desde luego, no es una opción en una aplicación real. La lista de clientes tiene que proceder de la lógica del negocio del componente, y ser renderizada de forma dinámica.
  • Otro problema es que la vista que muestra los datos de un cliente, por ahora, no nos muestra ningún dato, a excepción del propio id que se ha pasado como parámetro. Evidentemente, esto no nos sirve. Necesitamos poder ver toda la ficha del cliente.
  • Además, por ahora nos acepta cualquier valor en el parámetro, tanto si existe el cliente como si no. Esto también vamos a solucionarlo aquí.

Vamos, que aún hay muchas cosas que mejorar pero, desde luego, estamos en el camino correcto.

OBTENER LA LISTA DE CLIENTES

Este es el primer paso lógico. En el componente CustomersListComponent la lista de clientes debe ser obtenida en la lógica de negocio (customers-list.component.ts), en un arreglo que luego pueda ser pasado a la vista (customers-list.component.html), para que esta lo procese, lo muestre como deseamos y genere los enlaces adecuados.

Vamos a empezar por la lógica de negocio:

Observa el bloque resaltado. Tenemos un arreglo en JSON, con la lista de clientes. Si esto fuera una aplicación real, previamente habríamos conectado con una API para obtener este JSON pero, como aún no sabemos como conectar con API’s (es un tema que se desarrollará más adelante en el curso), así emulamos lo que habríamos obtenido. Lo que nos importa aquí es que ya tenemos la lista de clientes en un arreglo. Ahora tenemos que renderizar esa lista en la vista del componente (customers-list.component.html), y aquí es donde entran en juego algunas directivas de Angular. El código de la vista queda así:

En concreto, en este caso estamos usando la directiva *ngFor, que es la que nos proporciona Angular para crear bucles iterativos. Además la estamos usando con una directiva auxiliar que se llama ng-container. En la mayoría de los lengujes de programación que se emplean en desarrollo web (PHP o JavaScript, por ejemplo), cuando creamos un bucle, el cuerpo del mismo (las instrucciones que se repiten en cada iteración) va encerrado entre llaves ({ y }). En Angular el cuerpo del bucle se encierra entre <ng-container> y </ng-container>. Observa, además, la peculiar sintaxis de las directivas de Angular. En este ejemplo ves que *ngFor aparece como si fuera un atributo, o una propiedad de ng-container. Es una sintaxis que resulta un poco chocante al principio, pero es como la han diseñado los creadores de Angular y hay que conocerla.

El valor del «atributo» (lo digo así para familiarizarnos con esta sintaxis aunque, no es ningún atributo realmente) es la definición de un bucle que, a primer golpe de vista, ya nos damos cuenta que es muy similar a las definiciones de los bucles en ES6. La variable customers_list es el arreglo que se ha definido en la lógica del componente, y por eso lo tenemos disponible en la vista. Tal como está la sintaxis, lo que hacemos es recorrrer este arreglo (que tiene cuatro elementos) e ir recibiendo cada elemento en la variable customer, que declaramos en el bucle. Hasta aquí, casi nada nuevo. Como te he dicho, esto se parece muchísimo a los bucles en ES6, que seguro que ya conoces (si no te suena la construcción for...of te sugiero que le eches un vistazo a este artículo).

Cada elemento customer tiene tres miembros o propiedades (id, nombre y apellidos), porque esa es la estructura que tiene el arreglo en la lógica del componente. Como ya sabes, podemos acceder a un miembro de un elmento con la sintaxis ya conocida de separarlos con un punto (elemento.miembro). Con esto podemos obtener por separado cada uno de los miembros de cada elemento customer. Y el resto no tiene nada nuevo. Mediante interpolación de variables usamos el valor de cada miembro para contruir el enlace correspondiente a ese customer.

LA VISTA CON LOS DATOS DEL CLIENTE

Lo que hemos visto hasta ahora es una sintaxis un poco chcante al principio, pero, una vez que se analiza, es extremadamente simple. Aquí la cosa se pone un poquito más interesante, y también va a requerir más análisis por nuestra parte para comprenderla. Tienes que entender que aquí no solo tenemos que mostrar todos los datos de un cliente concreto, sino que, si hemos accedido con un identificador que no corresponde a ningún cliente existente, tenemos que informar de ello al usuario. Para eso debemos contar con una evaluación de condiciones, y Angular nos ofrece la directiva *ngIf, que vamos a conocer en este apartado para ver como nos queda CustomerDataComponent.

Pero vamos por partes. Una vez más, vamos a empezar por la lógica del componente (customer-data.component.ts):

Vamos a ver que tenemos aquí. En primer lugar tenemos un arreglo, con todos los datos (no solo el identificador, nombre y apellidos, si no la ficha completa) de todos los clientes. Y volvemos a lo mismo. En una aplicación real esta parte no sería necesaria porque, como en este script obtenemos un identificador, recuperaríamos, mediante una API, todos los datos de un cliente concreto pero, por ahora, ese no es el caso. Observa que este arreglo, que hemos llamado customers_full_list, se ha declarado como private. Esto es porque sólo lo vamos a usar dentro de la clase. Este arreglo, tal como está, con los datos de todos los clientes, no lo sacaremos a la vista.

Fíjate en la línea 49. Declaramos una variable llamada selected_customer, en la que almacenaremos todos los datos del cliente seleccionado. Esta variable sí es pública, por que esta sí será la que pasemos a la vista.

En la línea 54 recuperamos el identificador pasado por parámetro, como ya hemos hecho en los dos artículos anteriores. Aquí no hay nada nuevo. La novedad ahora es la siguiente: en la línea 55 comprobamos si en la lista existe un cliente con el identificador recibido. Si no lo hay, esta búqueda, tal como está, nos devuelve el valor undefined. En ese caso, se pone el identificador a 0. En caso de que no sea undefined, es decir, de que si exista un cliente con el identificador buscado, el objeto con todos sus datos se almacena en selected_customer, para que luego, en la vista, podamos recueprar sus miembros.

Así pues, ya tenemos el identificador (que será 0 si no existe el cliente con el id que habíamos pasado), y tenemos la variable selected_customer, que tendrá los datos del cliente, si este existe, o undefined, si no existe.

Por lo tanto, ya podemos pasar a la vista, en customer-data.component.html:

Aquí vemos varias cosas: en primer lugar ves que usamos la directiva auxiliar ng-container para acotar el código que debe ejecutarse si se cumple una condición que especificamos en la directiva *ngIf. Esto es parecido a lo que hacíamos en customers-list.component.html con *ngFor. La directiva auxiliar <ng-container></ng-container> la usaremos siempre para acotar condicionales o bucles. Habrá casos en los que un condicional no necesite ejecutar una serie de instrucciones si se cumple la condición. En esos casos (veremos algunos a lo largo del curso) no necesitaremos la directiva auxiliar, pero aquí si nos hace falta.

Como valor de *ngIf ponemos la condición que vamos a evaluar. En este caso vamos a comprobar si la variable identifier no vale 0, lo que nos estará diciendo que sí tenemos datos de un cliente registrado. Recuerda que, en la lógica del componente, si no existía el cliente, esta variable la poníamos a 0. Esta evaluación la hacemos con la parte identifier != "0". Además, los condicionales de las directivas, al igual que los de cualquier lenguaje de programación, admiten una alternativa (else), si no se cumple la condición. Esto lo hacemos con ; else noCustomerWarning, donde noCustomerWarning es un identificador que se refiere a una parte de código que se ejecutara, solo, si no se cumple la condición.

Así, si se cumple la condición, se ejecutarán las sentencias comprendidas entre <ng-container> y </ng-container>. Si no se cumple la condición se ejecutarán las sentencias englobadas bajo el identificador noCustomerWarning. Para establecer esas sentencias debemos usar otra directiva auxiliar, llamada ng-template. Observa como hemos definido un bloque con esta directiva en las líneas de la 13 a la 15. Además, en la línea 13 hemos usado el guarismo # para asignarle el identificador noCustomerWarning a la directiva. Esta es la forma de que la alternativa else del condicional reconozca cual es el bloque de código que debe ejecutar si no se cumple la condición.

También quiero llamar tu atención sobre otra particularidad de la sintaxis de la directiva condicional *ngIf. Observa que, en el bloque que se ejecuta si se cumple la condición (líneas de la 3 a la 10), hemos mostrado cada uno de los miembros de selected_customer, con la notación del punto, usando interpolación de variables. Es la forma de renderizar en la vista los valores de variables que proceden de la lógica. Sin embargo, en el condicional hemos evaluado la variable identifier sin las dobles llaves de la interpolación. Al igual que en las directivas de bucles, en las directivas condicionales las variables se invocan, directamente, con su nombre, sin necesidad de interpolarlas.

Por lo tanto, cuando se llega a la línea que abre el condicional, se evalúa la condición de si identifier no es igual a 0 (lo que nos dice que hay un cliente con ese identificador). Si se cumple esa condición, se ejecuta todo el código contenido entre <ng-container> y </ng-container>. Si la condición no se cumple (es decir, si identifier vale 0), se ejecuta el bloque alternativo comprendido entre <ng-template #noCustomerWarning> y </ng-template>.

Como ves, es una sintaxis, insisto, un poco peculiar para lo que estamos acostumbrados en otros lenguajes de programación, pero, una vez que le ves la lógica, es tan simple como cabría esperar.

CONCLUYENDO

Este artículo nos ha servido para empezar a conocer algunas de las directivas que emplea Angular para flexibilizar y potenciar el comportamiento de las vistas. Tienes el código de la aplicación, en su estado actual, disponible en este enlace. Espero verte en el próximo artículo, donde seguiremos aprendiendo cosas de Angular 5. Cómo práctica, puedes hacer lo mismo que hemos hecho con los clientes, en el módulo de proveedores. Puede que te cueste un poco la primera vez, o que cometas algún error. No importa. En seguida verás que es más fácil de lo que parece.

ATENCIÓN. Si buscas documentación en Internet verás que, en el contexto de Angular, a las directivas que empiezan con * (como es el caso de *ngIf y *ngFor) se las conoce, genéricamente, como directivas estructurales. Esto se debe a que realmente modifican la estructura del DOM de la página. Por ejemplo, en el caso de la vista de los datos del cliente, solo se ve una parte u otra, según se cumpla o no la condición. En realidad, la parte que no ves no es que esté oculta. Es que no existe. Esto puedes comprobarlo con el inspector de elementos de la consola de tu navegador.
   

Deja un comentario