Animaciones
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.
Las animaciones simples son más sencillas y eficientes de gestionar con CSS. Sin embargo esta API permite gestionar animaciones complejas como animar elementos en grupo o animar los cambios de página en Angular.
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 se necesita esto, 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.
La opción { optional: true } de la función query, sirve para cuando tenemos activado SSR, ya que los productos vendrán renderizados del servidor, por lo que la longitud del array se incrementa, pero intenta animarlos nada más empezar pero no hay ningún elemento entrando al DOM. Y si la función query no devuelve elementos da un error.
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.