Animation Route Changes in Angular

Introduction

Routing is the main concept in making Angular applications. Navigation from one component view to another is possible with routing. Angular has defined components for each routing path. It maps the corresponding component based on the routing module of the application. Applying animations between different route transition is an interesting concept. Animations enhance the user visibility towards their actions, looks catchy during the transition, etc. We just have to follow some simple steps for applying route transition animations:
  • Using the routing module, configure different routes. Configuring routes include defining the path and corresponding components.
  • Adding <router-outlet> to tell Angular where to place the specific component views during routing.
  • Define animations while route transition.

Import Route Module and Define the Route Configuration

To configure routes for these two links, we need to first import the module in the app-routing.module.ts file. 
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const appRoutes: Routes = [
  {
    path: 'home',
    component: HomePageComponent,
   
  },
  {
    path: 'contact',
    component: ContactPageComponent,
  
  },
  {
      path: 'help',
      component: HelpPageComponent,
  },
  {
      path: 'about',
      component: AboutPageComponent,
  },
   {
      path: 'public-sites',
      component: PublicSiteComponent,
  } 
   {
      path: '***',
      component: PageNotFoundComponent,
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(
     appRoutes,
     { onSameUrlNavigation: 'reload' })
  ],
  exports: [RouterModule]
})


Now we will add data property to our routing file. The data property is given to the AppComponent to identify the current route. Using this property only, animations are applied when we switch from one route to another. We will define the animation configuration with this data property. We have used key-value pairs for defining data property. The key can be anything but the value should be the same as animationTriggerName.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const appRoutes: Routes = [
  {
    path: 'home',
    component: HomePageComponent,
    data:{ animation: 'home'}
   
  },
  {
    path: 'contact',
    component: ContactPageComponent,
    data:{ animation: 'contact'}
  
  },
  {
      path: 'help',
      component: HelpPageComponent,
      data:{ animation: 'help'}
  }
]

Creating Animation

Now we will define the animation in a separate file called route-animation.ts. We can define animations in the component.ts file itself. But here we are creating a different file for the purpose of reusability. 

import {
   transition,
   trigger,
   query,
   style,
   animate,
   group,
   animateChild
} from '@angular/animations';
export const myAnimation =
   trigger('myRouteAnimate', [
         transition('home => contact', [
             query(':enter, :leave', 
                  style({ position: 'fixed',  width: '100%' }), 
                 ),
             group([
                  query(':enter', [
                      style({ transform: 'scale(2)' }), 
                      animate('0.5s', 
                      style({ transform: 'scale(1.5)' }))
                  ], { optional: true }),
                  query(':leave', [
                      style({ transform: 'scale(1)' }),
                      animate('0.5s ease-in-out', 
                      style({ transform: 'scale(2)' }))
                      ], { optional: true }),
              ])
        ]),
        transition('contact => help', [
              query(':enter, :leave', 
                  style({ position: 'fixed', width: '100%' }), 
                  { optional: true }),
              group([
                  query(':enter', [
                      style({ transform: 'translateY(100%)' }),
                      animate('0.5s ease-in-out', 
                      style({ transform: 'translateY(0%)' }))
                  ], { optional: true }),
                  query(':leave', [
                      style({ transform: 'translateY(0%)' }),
                      animate('0.5s ease-in-out', 
                      style({ transform: 'translateY(-100%)' }))
                  ], { optional: true }),
              ])
        ]),
        
       ]),
]);

Make a file and copy-paste the above code.
  • We have used the animation trigger name as myRouteAnimate. We will use the same name in the trigger used in the app.component.html file.
  • When a route animation is active, we have two selectors as :leave, :enter. 
  • :leave is used to select the previous page and :enter for the current page.
  • Use =>, <=> syntax to define the transition between different routes. We can even use * <=> * syntax to apply default animation for all the different navigation across our application.

Example for : enter and : leave selectors

import {
   transition,
   trigger,
   query,
   style,
   animate,
   group,
   animateChild
} from '@angular/animations';
export const myRouteAnimation =
   trigger('myAnimations', [
         transition('home => contact', [
             // Set default style for both enter and leave page
              query(':enter, :leave', 
                  style({ position: 'fixed',  width: '100%' }), 
                 ),
           // Animate the current new page
             query(':enter', [
                   animate('0.5s ease-in-out', style({ transform: ' scale(2)' })),
      ])
    ])
]);

We will see how we can animate the leaving page using the :leave selector.

import {
   transition,
   trigger,
   query,
   style,
   animate,
   group,
   animateChild
} from '@angular/animations';
export const myRouteAnimation =
   trigger('myAnimations', [
         transition('home => contact', [
             // Set default style for both enter and leave page
              query(':enter, :leave', 
                  style({ position: 'fixed',  width: '100%' }), 
                 ),
             //Animate the page leaving
             query(':leave', [
                   animate('0.5s ease-in-out', style({ transform: ' scale(1.5) translateX(100)' })),
      ],{optional:true})
    ])
]);


Using group() function

The group function is used to apply concurrent animations. Within this group() function, we will query both the views using :leave and :enter selectors.


  • We will mark some queries optional as leave query will not be present initially when the page loads. Use { optional: true } to mark :leave queries optional.
  • Using group() function we can run animations simultaneously.

import {
   transition,
   trigger,
   query,
   style,
   animate,
   group,
   animateChild
} from '@angular/animations';
export const myRouteAnimation =
   trigger('myAnimations', [
        transition('home => contact', [
              query(':enter, :leave', 
                  style({ position: 'fixed', width: '100%' }), 
                  { optional: true }),
              group([
                  query(':enter', [
                                animate('0.5s ease-in-out',  style({ transform: 'translateY(0%)' }))
                  ], { optional: true }),
                  query(':leave', [
                                animate('0.5s ease-in-out', style({ transform: 'translateY(-100%)' }))
                  ], { optional: true }),
              ])
        ]),
    

Setting Router Outlet

After creating route configuration and animations, we will tell Angular where to place the specific views based on different routes. For this, we will go to the app.component.html file and write the below code. We will define a container for <router-outlet> element. We will activate our animation trigger using the attribute directive of the <router-outlet>. 
This attribute directive activatedRouteData has information about active routes and its data property. We can access the data property which we set in the route configuration. o.activatedRouteData['animation'] will give the active route data name from the route config file. Based on the data property value, the [@myRouteAnimate] is set to different values.

<div [@myRouteAnimate]="o  &&  o.activatedRouteData  &&  o.activatedRouteData['animation']">
    <router-outlet #o="outlet"></router-outlet>
</div>

Now we will set the animation in the app.component.ts file and set the animations array to animation trigger name.

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
  animations: [
    myAnimation
    // write animation triggers here
  ]
})

Comments