Sintaxis para las vistas en Angular

  • Por
  • y  
Expresiones, binding, propiedades, eventos. Son muchas cosas las que podemos expresar en las vistas HTML de las aplicaciones Angular 2. Te ofrecemos una introducción general.

En los artículos anteriores del Manual de Angular 2 hemos analizado la estructura de una aplicación básica. Una de las cosas fundamentales que encontramos es el componente principal, sobre el cual hemos hecho pequeñas modificaciones para comprobar que las cosas están funcionando y comenzar a apreciar el poder de Angular.

Dentro del componente básico encontramos varios archivos y uno de ellos es el código HTML del componente, al que comúnmente nos referiremos con el nombre de "vista", denominación que viene por el patrón de arquitectura MVC. Pues bien, en ese código HTML, la vista, de manera declarativa podemos definir y usar muchas de las piezas con las que contamos en una aplicación: Vistas, propiedades, eventos, bindeo…

La novedad en Angular 2, para los que vienen de la versión anterior del framework, es que ahora podemos ser mucho más precisos sobre cómo queremos que la información fluya entre componentes, entre la vista y el modelo, etc. En este artículo vamos a ofrecer una primera aproximación general a todo lo que se puede declarar dentro de una vista, teniendo en cuenta que muchas de las cosas necesitarán artículos específicos para abordarlas en profundidad.

Nota: En este artículo, así como a lo largo del manual, hacemos uso constantemente de conceptos del MVC. Recordamos que existe un artículo genérico de lo que es el MVC, introducción al modelo vista controlador. De todos modos, en Angular 2 no se aplica una implementación perfectamente clara sobre el MVC. Existe una separación del código por responsabilidades, lo que ya nos aporta los beneficios de la arquitectura por capas, pero la implementación y características de estas capas no queda tan definida como podría darse en un framework backend. En este artículo y los siguientes verás que hacemos referencia a los modelos y realmente no es que exista una clase o algo concreto donde se coloca el código del modelo. Ese modelo realmente se genera desde el controlador y para ello el controlador puede obtener datos de diversas fuentes, como servicios web. Esos datos, tanto propiedades como métodos, se podrán usar desde la vista. Es algo más parecido a un VW (View Model), o sea, un modelo para la vista, que se crea en el controlador. Por otra parte, tampoco existe un controlador, sino una clase que implementa el View Model de cada componente. En resumen, conocer el MVC te ayudará a entender la arquitectura propuesta por Angular 2 y apreciar sus beneficios, pero debemos mantener la mente abierta para no confundirnos con conocimientos que ya podamos tener de otros frameworks.

Piezas declarables en una vista

Comenzaremos por describir las cosas que disponemos para su declaración en una vista, de modo que todos podamos usar un único vocabulario.

  • Propiedad: Cualquier valor que podemos asignar por medio de un atributo del HTML. Ese elemento puede ser simplemente un atributo del HTML estándar, un atributo implementado mediante el propio Angular 2 o un atributo personalizado, creado para un componente en específico.
  • Expresión: Es un volcado de cualquier información en el texto de la página, como contenido a cualquier etiqueta. La expresión es una declaración que Angular procesará y sustituirá por su valor, pudiendo realizar pequeñas operaciones.
  • Binding: Es un enlace entre el modelo y la vista. Mediante un binding si un dato cambia en el modelo, ese cambio se representa en la vista. Pero además en Angular se introduce el "doble binding", por el cual si un valor se modifica en la vista, también viaja hacia el modelo.
  • Evento: es un suceso que ocurre y para el cual se pueden definir manejadores, que son funciones que se ejecutarán como respuesta a ese suceso.

Nota: Generalmente cuando hablemos de "binding" en la mayoría de las ocasiones nos referimos a "doble binding", que es la principal novedad que trajo Angular 1 y que le produjo tanto éxito para este framework.

El problema del doble binding es que tiene un coste en tiempo de procesamiento, por lo que si la aplicación es muy compleja y se producen muchos enlaces, su velocidad puede verse afectada. Es el motivo por el que se han producido nuevas sintaxis para poder expresar bindings de varios tipos, de una y de dos direcciones. Dicho de otra manera, ahora se entrega al programador el control del flujo de la información, para que éste pueda optimizar el rendimiento de la aplicación.

Flujo de la información de la vista al modelo y modelo a vista

El programador ahora será capaz de expresar cuándo una información debe ir del modelo hacia la vista y cuándo debe ir desde la vista al modelo. Para ello usamos las anteriores "piezas" o "herramientas" en el HTML, las cuales tienen definida de antemano un sentido para el flujo de los datos.

En el siguiente diagrama puedes ver un resumen del flujo de la información disponible en Angular, junto con las piezas donde podemos encontrarlo y su sintaxis.

  1. Las propiedades tienen un flujo desde el modelo a la vista. Una información disponible en el modelo se puede asignar como valor en un elemento del HTML mediante una propiedad, usando la notación corchetes. Por ej: [propiedad]
  2. Las expresiones también viajan desde el modelo a la vista. La diferencia de las propiedades es que en este caso las usamos como contenido de un elemento y además que se expresan con dobles llaves. Por ej: {{expresión}}
  3. El binding (a dos sentidos, o doble binding) lo expresamos entre corchetes y paréntesis. En este caso la información fluye en ambos sentidos, desde el modelo a la vista y desde la vista al modelo. Por ej: [(ngBind)]
  4. Los eventos no es que necesariamente hagan fluir un dato, pero sí se considera un flujo de aplicación, en este caso de la vista al modelo, ya que se originan en la vista y generalmente sirven para ejecutar métodos que acabarán modificando cosas del modelo. Por ej: (evento)

Nota: Como ves, ahora existen diversas sintaxis para expresar cosas en las vistas. Quizás nos resulte extraño, pero enseguida nos familiarizaremos. La notación más rara es la que usamos para expresar un binding en dos direcciones [(ngBing)], pero una manera sencilla de acordarnos de ella es con su denominación anglosajona "banana in a box". Los paréntesis parecen una banana, dentro de los corchetes, que parecen una caja.

Ejemplos de sintaxis utilizada en vistas de Angular 2

Realmente ya hemos visto ejemplos de buena parte de las piezas posibles a declarar en una vista. Si te fijas en el artículo anterior dedicado a la Introducción a los componentes en Angular 2. Ahora les podemos dar nombres a cada uno de los elementos encontrados.

Propiedades:
Era el caso de la propiedad "hidden" que usamos para mostrar / ocultar determinados elementos. En este caso, hidden no es una propiedad estándar del HTML, sino que está generada por Angular 2 y disponible para aplicar tanto en etiquetas HTML comunes como en componentes personalizados.

<p [hidden]="!visible">Adiós</p>

También podríamos aplicar valores a atributos del HTML con datos que están en propiedades del modelo, aunque no soporta todos los atributos del HTML estándar. Por ejemplo, podríamos asignar una clase CSS (class) con lo que tuviésemos en una propiedad del modelo llamada "clase".

<div [class]="clase">Una clase marcada por el modelo</div>

O el enlace de un enlace podríamos también definirlo desde una variable del modelo con algo como esto:

<a [href]="enlace">Pulsa aquí</a>

Pero en general, el uso más corriente que se dará a esta forma de definir una propiedad personalizada de un componente, de modo que podamos personalizar el estado o comportamiento del componente mediante datos que tengamos en el modelo. Veremos este caso más adelante cuando analicemos con mayor detalle los componentes.

Lo que de momento debe quedar claro es que las propiedades van desde el modelo a la vista y, por tanto, si se modifica el valor de una propiedad en el modelo, también se modificará la vista. Pero , si dentro de la vista se modifica una propiedad no viajará al modelo automáticamente, pues el enlace es de una sola dirección.

Expresiones:
Es el caso de la propiedad del modelo "title" que se vuelca como contenido de la página en el encabezamiento.

<h1>
  {{title}}
</h1>

Simplemente existe esa sustitución del valor de la propiedad, colocándose en el texto de la página. El enlace es de una única dirección, desde el modelo a la vista. En la vista tampoco habría posibilidad de modificar nada, porque es un simple texto.

El caso de propiedades del HTML con valores que vienen del modelo también podríamos implementarlo por medio de expresiones, tal como sigue.

<a href="{{enlace}}">Clic aquí</a>

Nota: Las dos alternativas (usar expresiones con las llaves o los corchetes para propiedades, como hemos visto para el ejemplo de un href de un enlace cuyo valor traes del modelo) funcionan exactamente igual, no obstante para algunos casos será mejor usar la sintaxis de propiedades en vez de la de expresiones, como es el caso del enlace. Algo que entenderemos mejor cuando lleguemos al sistema de rutas.

Eventos:
Esto también lo vimos en el artículo anterior, cuando asociamos un comportamiento al botón. Indicamos entre paréntesis el tipo de evento y como valor el código que se debe de ejecutar, o mejor, la función que se va a ejecutar para procesar el evento.

<button (click)="decirAdios()">Decir adiós</button>

Con respecto a Angular 1.x entenderás que ahora todas las directivas como ng-click desaparecen, dado que ahora los eventos solo los tienes que declarar con los paréntesis. Esto es interesante ya de entrada, porque nos permite definir de una única manera cualquier evento estándar del navegador, pero es más interesante todavía cuando comencemos a usar componentes personalizados, creados por nosotros, que podrán disparar también eventos personalizados. Capturar esos eventos personalizados será tan fácil como capturar los eventos estándar del HTML.

Binding:
Para este último caso no hemos visto todavía una implementación de ejemplo, pero lo vamos a conseguir muy fácilmente. Como se dijo, usamos la notación "banana in a box" para conseguir este comportamiento de binding en dos direcciones. Los datos viajan de la vista al modelo y del modelo a la vista.

<p>
  ¿Cómo te llamas?  <input type="text" [(ngModel)]="quien">
</p>

En este caso, desde el HTML estaríamos creando una propiedad dentro del modelo. Es decir, aunque no declaremos la propiedad "quien" en el Javascript, por el simple hecho de usarla en la estructura de binding va a producir que se declare automáticamente y se inicialice con lo que haya escrito en el campo de texto. Si la declaramos, o la inicializamos desde la clase que hace las veces de controlador, tanto mejor, pero no será necesario.

Nota: La notación "banana in a box" tiene una explicación y es que usa tanto el flujo de datos desde el modelo a la vista, que conseguimos con los corchetes para las propiedades, como el flujo desde la vista al modelo que conseguimos con los paréntesis para los eventos.

Para quien conozca Angular 1, ngModel funciona exactamente igual que la antigua directiva. En resumen, le asignamos el nombre de una propiedad en el modelo, en este caso "quien", con la que se va a conocer ese dato. A partir de entonces lo que haya escrito en el campo de texto viajará de la vista al modelo y si cambia en el modelo también se actualizará la vista, produciendo el binding en las dos direcciones.

Si quisiéramos visualizar ese dato en algún otro de la vista, por ejemplo en un párrafo, usaríamos una expresión. Por ejemplo:

<p>
  Hola {{quien}}
</p>

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Autor

Alberto Basalo

Alberto Basalo es experto en Angular y otras tecnologías basadas en Javascript, como NodeJS y MongoDB. Es director de Ágora Binaria, empresa dedicada al desarrollo de aplicaciones y a la formación a través de Academia Binaria.

Compartir

Comentarios

migüel

18/4/2017
post perfecto
Se entiende perfectamente, incluso teniendo en cuenta los cambios de versiones. Gracias por vuestra ayuda^^.

Oscar

10/4/2019
FormsModule
Se podría agregar que es necesario incluir FormsModule dentro de app.module.ts, en la sección superior junto a los otros "import" y también en la sección imports dentro de la declaración de @NgModule.