Angular 2/5 - Router Animation Tutorial & Example
Tutorial built with Angular 5.0.3
Other versions available:
In this tutorial I'll show you how you can implement animations between routes in Angular 2/5 and TypeScript.
Project code is available on GitHub at https://github.com/cornflourblue/angular2-animation-tutorial-example.
Difference Between Angular 2/5 Animations and AngularJS Animations
Animations in Angular 2/5 work completely differently to Angular 1, in Angular 1 there are css class hooks that you can use to animate elements into view and out of view, whereas in Angular 2/5 animations are implemented inside your components using a set of functions (trigger, state, animate, transition, style) from the new '@angular/animations' package.
Animation styles are still defined using CSS but they're written in TypeScript using JSON objects (TSON?) instead of CSS/LESS files, there's also a new Angular Animation DSL (Domain Specific Language) that has been created to define different states and transitions between states. I won't go too much into the details of all the new bits and pieces of the animation system since you can find all that information on the angular docs site, instead I'll focus on an example and how to get animations working between routes.
Don't feel bad if the new angular animation system has had you banging your head against the wall in frustration, it's taken me an embarrassingly long time to get my head around and I'm still coming to grips with it!
Angular 2/5 Animations Tutorial Demo
Here's the tutorial example application in action, it uses a fade transition between top level tabs and a slide in/out transition on the products page for adding and editing a product.
(See on Plunker at https://plnkr.co/edit/AfIB1i?p=preview)
Running the Angular 2/5 Animation Tutorial Demo Locally
- Install NodeJS and NPM from https://nodejs.org/en/download/, you can check the versions you have installed by running
node -v
andnpm -v
from the command line.
- Download the project source code from https://github.com/cornflourblue/angular2-animation-tutorial-example
- Install all required npm packages by running
npm install
from the command line in the project root folder (where the package.json is located).
- Start the application by running
npm start
from the command line in the project root folder.
Let's stay focused on the animations
I tried to make the example a real world-ish application so it contains a few services and other bits and pieces but I'm just going to focus on the animations in this post and how to add them to your Angular 2/5 routes.
Import BrowserAnimationsModule into app.module.ts
With the release of Angular 4, animations were split out from the angular core into their own module, so to use animations you have to import the BrowserAnimationsModule at the top of your app.module.ts file:
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
And add the BrowserAnimationsModule to the list of imports in your @NgModule metadata:
@NgModule({
imports: [
...
BrowserAnimationsModule
],
...
})
export class AppModule { }
The first import makes BrowserAnimationsModule available to code inside the app.module.ts file, and the second import makes all the public functions from BrowserAnimationsModule available to other components in AppModule
.
Define Your Angular 2/5 Animations
Animations can be defined directly inside your components but I prefer to separate them into their own files, this allows you to re-use the animations anywhere in your application and makes component code much cleaner as it maintains a good separation of concerns.
In the example I've put animations in the app/_animations
folder, I like to prefix non-feature folders with an underscore '_' to group them together at the top and separate them from feature folders. Feature folders contain code for views / routes in your application such as home and products, non-feature folders contain shared code such as services, animations, directives, css etc, basically everything else.
Angular 2/5 Fade In Animation
The fade in animation that's used by the home component and product list component in the example.
// import the required animation functions from the angular animations module
import { trigger, state, animate, transition, style } from '@angular/animations';
export const fadeInAnimation =
// trigger name for attaching this animation to an element using the [@triggerName] syntax
trigger('fadeInAnimation', [
// route 'enter' transition
transition(':enter', [
// css styles at start of transition
style({ opacity: 0 }),
// animation and styles at end of transition
animate('.3s', style({ opacity: 1 }))
]),
]);
Angular 2/5 Slide In/Out Animation
The slide in/out animation that's used by the product add/edit component in the example.
// import the required animation functions from the angular animations module
import { trigger, state, animate, transition, style } from '@angular/animations';
export const slideInOutAnimation =
// trigger name for attaching this animation to an element using the [@triggerName] syntax
trigger('slideInOutAnimation', [
// end state styles for route container (host)
state('*', style({
// the view covers the whole screen with a semi tranparent background
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.8)'
})),
// route 'enter' transition
transition(':enter', [
// styles at start of transition
style({
// start with the content positioned off the right of the screen,
// -400% is required instead of -100% because the negative position adds to the width of the element
right: '-400%',
// start with background opacity set to 0 (invisible)
backgroundColor: 'rgba(0, 0, 0, 0)'
}),
// animation and styles at end of transition
animate('.5s ease-in-out', style({
// transition the right position to 0 which slides the content into view
right: 0,
// transition the background opacity to 0.8 to fade it in
backgroundColor: 'rgba(0, 0, 0, 0.8)'
}))
]),
// route 'leave' transition
transition(':leave', [
// animation and styles at end of transition
animate('.5s ease-in-out', style({
// transition the right position to -400% which slides the content out of view
right: '-400%',
// transition the background opacity to 0 to fade it out
backgroundColor: 'rgba(0, 0, 0, 0)'
}))
])
]);
Attach the Angular Animations to Your Routed Components
With the animations cleanly separated into their own files it's easy to attach them to your angular routes, all you need to do is import the animation you want to use and add it to your @Component metadata.
Angular 2/5 Home Component with Fade In Animation
The home component from the example with the fade in animation attached.
import { Component } from '@angular/core';
// import fade in animation
import { fadeInAnimation } from '../_animations/index';
@Component({
moduleId: module.id.toString(),
templateUrl: 'home.component.html',
// make fade in animation available to this component
animations: [fadeInAnimation],
// attach the fade in animation to the host (root) element of this component
host: { '[@fadeInAnimation]': '' }
})
export class HomeComponent {
}
Angular 2/5 Product List Component with Fade In Animation
The product list component from the example with the fade in animation attached.
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { ProductService, PubSubService } from '../_services/index';
// import fade in animation
import { fadeInAnimation } from '../_animations/index';
@Component({
moduleId: module.id.toString(),
templateUrl: 'product-list.component.html',
// make fade in animation available to this component
animations: [fadeInAnimation],
// attach the fade in animation to the host (root) element of this component
host: { '[@fadeInAnimation]': '' }
})
export class ProductListComponent implements OnInit, OnDestroy {
products: any[];
subscription: Subscription;
constructor(
private productService: ProductService,
private pubSubService: PubSubService) { }
deleteProduct(id: number) {
this.productService.delete(id);
this.loadProducts();
}
ngOnInit() {
this.loadProducts();
// reload products when updated
this.subscription = this.pubSubService.on('products-updated').subscribe(() => this.loadProducts());
}
ngOnDestroy() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
private loadProducts() {
this.products = this.productService.getAll();
}
}
Angular 2/5 Product Add/Edit Component with Slide In/Out Animation
The product add/edit component from the example with the slide in/out animation attached.
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { ProductService, PubSubService } from '../_services/index';
// import slide in/out animation
import { slideInOutAnimation } from '../_animations/index';
@Component({
moduleId: module.id.toString(),
templateUrl: 'product-add-edit.component.html',
// make slide in/out animation available to this component
animations: [slideInOutAnimation],
// attach the slide in/out animation to the host (root) element of this component
host: { '[@slideInOutAnimation]': '' }
})
export class ProductAddEditComponent implements OnInit {
title = 'Add Product';
product: any = {};
constructor(
private route: ActivatedRoute,
private router: Router,
private productService: ProductService,
private pubSubService: PubSubService) { }
ngOnInit() {
let productId = Number(this.route.snapshot.params['id']);
if (productId) {
this.title = 'Edit Product';
this.product = this.productService.getById(productId);
}
}
saveProduct() {
// save product
this.productService.save(this.product);
// redirect to users view
this.router.navigate(['products']);
// publish event so list controller can refresh
this.pubSubService.publish('products-updated');
}
}
Need Some Angular 2 Help?
Search fiverr for freelance Angular 2 developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!