Animaciones

<< Server Side Rendering

El módulo de animaciones de Angular permite crear animaciones, tanto de elementos que hay en la aplicación, como de transición entre las diferentes páginas. Sigue el estándar Web Animations, por lo que las animaciones tienen un rendimiento nativo.

Para activar las animaciones, añade en el array providers (app.config.ts) la llamada a la función provideAnimationsAsync:

La función provideAnimationsAsync carga el módulo de animaciones de Angular en diferido, separando el código y cargándolo después del código inicial de la aplicación. La única desventaja es que esto puede hacer que no funcione alguna animación que pongamos nada más cargue la aplicación. Solo si se necesita eso, habría que usar provideAnimations en su lugar (la carga inicial de la aplicación será más pesada también).

Animando elementos

Las animaciones en los elementos de la plantilla se gestionan con triggers. Para crear un trigger en un elemento le añadimos un atributo cuyo nombre empiece por '@'.

Si le añadimos únicamente el atributo, podremos animar cuando el elemento entre y salga del DOM:

Le podemos asociar también un estado. Un estado es un string que puede ir cambiando de valor. De esta forma, podemos animar los cambios entre diferentes estados.

Estados :enter y :leave

Para los elementos que estén dependan de un @if o de un @for para entrar o salir del DOM pueden utilizar los estados especiales :enter y :leave para animar esas entradas y salidas.

Para crear la animación seguimos los siguientes pasos:

  • Dentro del decorador @Component, añadimos la propiedad animations cuyo valor será un array de triggers.
  • Por cada trigger que hayamos asociado a un elemento en la plantilla que queramos animar, llamamos a la función trigger, le pasamos el nombre del mismo (sin la @) y una lista de transiciones entre estados para animar.
  • Dentro de la función trigger, añadimos las transiciones llamando a la función transition. En el caso del estado :enter le añadiremos un estado inicial con la función style, y después una animación con la función animate hacia el estado final.

En el siguiente ejemplo, los productos de la lista estarán desplazados 100px a la izquierda y serán invisibles, para a continuación, durante 500ms, ir a la posición que les corresponde volviendose visibles gradualmente.

Transiciones entre estados

Además de los estados especiales :enter y :leave, podemos crear nuestros propios estados. Para ello, vinculamos el trigger de la animación a una propiedad que contenga un string o un booleano con el estado del elemento. Por ejemplo, vamos a crear un estado 'selected' para el producto que indicará si está seleccionado.

En este caso definiremos el estilo que tendrá en cada determinado estado donde queramos modificar o añadir algo al estilo predeterminado usando la función state. Después establecemos las transiciones entre estados y la duración y estilo de la animación.

Si en lugar de un booleano, usamos un string como valor, podríamos crear varios estados (valor del string) y establecer transiciones entre ellos.

Animando elementos internos: query()

La función query permite animar elementos que hay dentro del elemento que tiene el trigger de animación. En este caso vamos a modificar la animación de aparición de productos para que aparezcan uno detrás de otro (con un pequeño retardo), en lugar de todos a la vez.

El trigger tiene que estar ahora en un elemento que contenga a los elementos de tipo product-item que queremos animar. Envolveremos la animación con la función stagger, que permite establecer un retardo entre un elemento y otro a la hora de aplicarle la animación. En este caso el retardo será de 100ms.

En nuestro ejemplo particular, como el elemento padre (.card-block) está fuera del bloque @if. Si intentamos animar los productos cuando entra el elemento padre al DOM, no habrá productos, por lo que no animará nada (además devolverá un error al no devolver nada la función query). En este caso vincularemos el trigger a la longitud del array de productos a mostrar, y usaremos el cambio de estado :increment. Es decir, cuando aumente el número de productos, animaremos aquellos productos que se acaban de insertar en el DOM.

Esta animación no funcionará si usamos SSR y cargamos directamente la página de productos, ya que la hidratación hará que Angular en el cliente no detecte ningún cambio en el número de productos mostrados. Para ello tendríamos que usar otra estrategia, ya que quedaría mal, mostrar la lista de productos para unos milisegundos después que se oculten y se anime su entrada.

Animando transiciones entre páginas

Para animar cambios de página, tenemos que introducir algún tipo de información en las rutas que permita distinguirlas a la hora de aplicarles una animación. En este caso les añadiremos un dato llamado animation mediante la propiedad data (es un objeto que contiene datos extras que les podemos pasar a las rutas).

Después, desde el componente AppComponent, que contiene el elemento router-outlet, crearemos una referencia a dicho elemento y la usaremos para obtener el nombre de la animación que hemos establecido en ciertas rutas y aplicar un trigger al elemento padre que pueda controlar los cambios de rutas.

Para que el componente de la página mantenga su ancho original y no se expanda al 100% de la página, el componente padre (div.container) debe tener en este caso el la propiedad position:relative.

<< Server Side Rendering