Angular: las plantillas, bindings y directivas
Las plantillas
Cada componente que produce un resultado visualizable en una página web, lo hace a través de su plantilla. Esta plantilla se corresponde con su vista en la página única de la aplicación mono página.
Esta plantilla se puede codificar en el componente (lo calificaremos como plantilla insertada, en inglés «embedded»), o externalizada en un archivo separado. Por supuesto, es realmente preferible crear plantillas externalizadas, que permiten una mejor organización y por lo tanto, una mejor legibilidad del código.
La plantilla de un componente se integra en la página web única de la aplicación, de dos maneras diferentes:
-
De manera estática, en el lugar donde las etiquetas de apertura y cierre definidas por su selector aparecen en otra plantilla o en la página raíz src/index.html: su selector se declara en la propiedad selector del objeto que configura (que decora) el componente.
-
O de manera dinámica, cuando el componente se invoca por el controlador y su vista se asocia a una etiqueta llamada <router-outlet> (ver el capítulo Angular y la gestión de las rutas internas).
Nos interesamos en primer lugar por la integración de las plantillas de manera estática. Suponga un componente llamado MycomponentComponent, creado con Angular CLI.
A continuación se muestra el esqueleto de este componente:
import { Component } from '@angular/core';
@Component({
selector: "app-mycomponent",
templateUrl: "Mycomponent.component.html",
styleUrls: [ "Mycomponent.component.css" ]
})
export class MycomponentComponent {
...
}
Su plantilla (es decir, su vista), que se define en el archivo Mycomponent.component.html, se integrará en el lugar en el que aparecerán las etiquetas <app-mycomponent></app-mycomponent> (forman un component directive) en otra plantilla o en la página src/index.html.
Por lo tanto, este funcionamiento implica que las etiquetas propias de Angular se van a integrar en diferentes códigos HTML de su aplicación (página src/index.html de más alto nivel, plantillas de los componentes). Estas etiquetas (y también...
Data bindings entre el componente y la plantilla
Para relacionar una variable (o un método en el caso de la gestión de un listener de eventos) del componente en la plantilla, existen varios tipos de unión (de data bindings):
-
La interpolación: una variable escalar del componente se inyecta en la plantilla.
-
El property binding: Angular tiene en cuenta un atributo de una etiqueta, que se corresponde con un atributo existente de una etiqueta HTML o con un nuevo atributo.
-
El event binding: un método del componente se llama a través de un evento soportado por Angular.
-
El two-way data binding: una variable del componente se relaciona de manera bidireccional a una interfaz de entrada o de selección de la plantilla.
1. Acceso a los elementos del DOM
Antes de cualquier cosa, veamos cómo Angular permite hacer referencia simplemente a los elementos del DOM, a fin de acceder a ellos y eventualmente, modificarlo.
El DOM representa la jerarquía de los objetos creados por las etiquetas HTML, así como sus atributos y la información textual que circunscribe (y otra información) en memoria del navegador. Los objetos se corresponden con las etiquetas HTML se llaman elementos.
Angular ofrece la posibilidad de hacer aparecer en una etiqueta HTML, una referencia al elemento del DOM con el que se corresponde. A continuación, esta referencia se podrá utilizar en el código. De manera sintáctica, una referencia se prefija por una almohadilla.
Para ilustrar esto, a continuación se muestra la creación de una referencia llamada image asociada a la imagen que se muestra en la plantilla (con Angular CLI, los recursos, entre ellos las imágenes, se deben almacenar en la carpeta src/assets):
<img #imageRef src="assets/Angular.png" />
Por otro lado, gracias a las directivas de atributo, es posible acceder a los atributos de un elemento del DOM (se corresponde con una etiqueta HTML), para modificarlos (ver la sección Las directivas de atributo).
2. Interpolación de una variable en una plantilla
La interpolación de una variable de un componente (de hecho, una propiedad de una clase TypeScript) en una plantilla HTML, se realiza gracias a las dobles llaves.
A continuación se muestra un ejemplo en el que el componente AppComponent tiene una variable llamada who, cuyo valor...
Las directivas
Una directiva es una nueva etiqueta o un nuevo atributo soportado por Angular e insertado respectivamente en el código HTML o en una etiqueta.
Por lo tanto, las directivas extienden el lenguaje HTML.
Globalmente hay dos tipos de directivas (el segundo tipo se puede dividir en subtipos):
-
Las directivas «componentes» (directivas de componentes), representadas por nuevas etiquetas, que insertan las vistas de los componentes en el flujo HTML: se fusionan con la implementación de los componentes.
-
Las directivas se dan en los atributos a una etiqueta y que condicionan su visualización (y más generalmente, su comportamiento).
Las directivas dadas como atributos a una etiqueta, se declinan en diferentes facetas:
-
Las directivas estructurales (structural directives), que permiten mostrar cero, una o varias veces las etiquetas en las que aparezcan.
-
Las otras directivas, llamadas globalmente directivas de atributo (attribute directives), que permiten:
-
Modificar la apariencia del elemento asociado a la etiqueta, modificando sus atributos en el DOM (con la condición o no de que exista un evento, y por ejemplo, en el marco del propertybinding).
-
Establecer una operación particular asociada a la etiqueta, cuando esta se activa (por ejemplo, la directiva [(ngModel)], que permite gestionar el two-way data binding, o la directiva [routerLink], que permite invocar el controlador en la activación de un ancla).
Antes de examinar estas directivas más en detalle, a continuación se muestra un pequeño aperitivo de las diferentes sintaxis:
-
Los ángulos enmarcan una directiva de componente: <Directiva>.
-
Un asterisco utiliza como prefijo de una directiva estructural: *Directiva="...".
-
Los corchetes enmarcan una directiva de atributo, con un valor a evaluar: [Directiva]="..." (y si no hay valor a evaluar, el nombre de la directiva se especifica directamente).
1. Las directivas estructurales
Las directivas estructurales que permiten controlar la producción de las etiquetas HTML en una plantilla.
Sintácticamente, se introducen por un asterisco:
-
*ngFor: controla la iteración de una etiqueta.
-
*ngIf: controla la visualización de una etiqueta.
a. La directiva *ngFor
La directiva *ngFor insertada en una etiqueta HTML, permite (por defecto) producir esta etiqueta para cada elemento (ítem) de una lista...
Los pipes
Dentro de una plantilla, los pipes (los filtros) permiten transformar un dato: el dato inicial se proporciona en la entrada del pipe, que genera como salida el dato transformado según la sintaxis:
<datoDeEntrada> | <datoDeSalida>
Solo hay algunos pipes ofrecidos por Angular, principalmente UpperCasePipe y LowerCasePipe.
Por ejemplo, en una plantilla, puede transformar en mayúsculas todos los caracteres de la cadena contenida en la variable interpolada nombre:
{{ nombre | UpperCase}}
Pero los pipes propuestos por Angular (en el momento en el que se escribe este libro), son muy escasos. También puede crear sus propios pipes (por ejemplo, un pipe muy útil que ordena los elementos de una colección en una de sus propiedades).
Para hacer esto, utilice el comando de Angular CLI que produce el esqueleto de un pipe:
ng generate pipe <nombreDelPipe>
o su versión abreviada:
ng g p <nombreDelPipe>
A continuación se muestra el resultado de este comando, usando como nombre de pipe, sort:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'sort'
})
export class SortPipe implements PipeTransform {
transform(value: any, args?: any): any {
return null;
}
}
En este esqueleto, la transformación operada por el pipe se gestiona por el método transform(), que recibe como argumentos:
-
La entrada dada en el pipe (por defecto no importa qué).
-
Una lista indeterminada de argumentos.
Y no devuelve nada por el momento.
Por lo tanto, quiere crear un pipe llamado sort, que ordene...
Ejemplo de resumen: un formulario de autenticación
Para ilustrar de manera resumida la mayor parte de los bindings que hemos descrito, a continuación se muestra el ejemplo del componente AuthComponent. Este es un esqueleto posible.
A continuación se muestran los archivos que componen este ejemplo:
-
AUTH/src/app/app.component.ts (no presentado): el componente principal.
-
AUTH/src/app/app.component.html: la plantilla del componente principal.
-
AUTH/src/app/auth/auth.component.ts: el componente de autenticación.
-
AUTH/src/app/auth/auth.component.html: la plantilla del componente de autenticación.
-
AUTH/src/app/app.module.ts (no presentado): el módulo que agrupa el código de la aplicación.
La plantilla del componente principal (archivo app.component.html) es muy sencilla:
<app-auth></app-auth>
A continuación se muestra el esqueleto del componente (archivo auth/auth.component.ts), que gestiona un formulario de autenticación.
Este componente implementa:
-
Las cadenas de caracteres de identificación login y password.
-
El booleano isLoggedIn (gestionado en otro lugar), que guarda si el internauta ya está autenticado.
-
El método onSubmit() se llama cuando el formulario se envía para su validación.
-
El método logout() que guarda la desconexión del internauta.
import { Component } from '@angular/core';
import...
El hilo rojo: creación de un componente que muestra los productos
Para empezar a desarrollar el lado cliente (el «cliente-side») de la aplicación de e-commerce, cree con Angular CLI un proyecto llamado OnlineSalesStep1.
ng new OnlineSalesStep1
Angular CLI crea un módulo que inicia («bootstrapping») un primer componente, que es el componente principal de la aplicación (en esta etapa).
Este componente se corresponde con la primera versión de ProductDisplayComponent (ver la sección Anidación de las plantillas).
Se generan diferentes archivos, y más particularmente (por orden de creación):
-
src/app/app.component.css: este archivo contiene la hoja de estilos asociada a la plantilla del componente principal.
-
src/app/app.component.html: este archivo contiene la plantilla del componente principal (su vista).
-
src/app/app.component.ts: este archivo contiene la clase TypeScript que implementa las operaciones de negocio del componente principal.
-
src/app/app.module.ts: este archivo especifica la lista de los componentes gestionados por el módulo actual.
-
src/index.html: la página web de la aplicación en la que se incluyen las diferentes plantillas de los componentes en una estructura de árbol.
-
src/main.ts: el código que inicia (bootstrapper) el módulo raíz de la aplicación.
Ahora va a elaborar el componente que muestra la información de los productos a vender, contenidos en una colección creada en un primer momento «en duro (hardware)» en el código (como verá en el capítulo Angular y la conexión a Node.js: los servicios, cómo Angular puede acceder a una base de datos MongoDB en la que se gestionará esta colección).
1. El componente
Cree el esqueleto del componente ProductDisplayComponent con el comando ng de Angular CLI:
ng g c productDisplay
se crean cuatro archivos en la carpeta src/app/product-display:
-
product-display.component.ts: este archivo contiene la clase TypeScript que implementa el componente.
-
product-display.component.html: este archivo contiene la plantilla del componente.
-
product-display.component.css: este archivo contiene la hoja de estilos asociada a la plantilla.
-
product-display.component.spec.ts: este archivo contiene la especificación de las pruebas unitarias.
Ahora va a completar los tres primeros...
Conocimientos adquiridos en este capítulo
En este capítulo, hemos estudiado la construcción de las vistas de los componentes, es decir las plantillas. En primer lugar, hemos visto cómo estás plantillas se integran las unas en los otras, a partir de la página HTML de más alto nivel src/index.html, para formar la única página de la aplicación mono página.
Después hemos descrito el mecanismo que permite relacionar un atributo o un método de la clase TypeScript, que implementa un componente en su plantilla. Por lo tanto, este enlace (este «binding») relaciona la vista (la plantilla) con el modelo (la implementación en una clase TypeScript de las operaciones de negocio del componente).
Hemos declinado este data binding según diferentes facetas:
-
La interpolación de una variable en la plantilla.
-
La gestión de un atributo de una etiqueta (ya sea sobrecargando un atributo existente de la etiqueta o para gestionar un nuevo atributo) por Angular (el property binding).
-
La llamada de un método del componente (más exactamente, de la clase que la implementa), a partir de un evento capturado por la plantilla (el event binding).
-
El acoplamiento bidireccional de una variable entre la vista y el modelo de un componente de tal tipo, que la actualización de esta variable en la clase TypeScript se repercute automáticamente...