Angular Tutorial: Simple Toast Animation

by | Jul 22, 2019

In this tutorial, I am going to work through creating a simple toasty using Angular’s animation features. If you aren’t familiar with the term “toasty”, it’s just a notification message that pops up on your screen like a piece of toast in a toaster. This will cover some of the basics of Angular’s animation API. First, let’s see what Angular’s documentation says about animations.

 

Angular Animation Functionality Per Angular.io

“Angular’s animation system is built on CSS functionality, which means you can animate any property that the browser considers animatable. This includes positions, sizes, transforms, colors, borders, and more.”

“The functional API provided by the @angular/animations module provides a domain-specific language (DSL) for creating and controlling animations in Angular applications.”

https://angular.io/guide/animations

 

ng-example

 This example is within the context of an “ng-example” series I have written for in the past. All of this code and additional examples can be found in a GitHub repo. I place each example in its own module and will skip over the part generating the module and component (in this case an AnimationExampleModule and AnimationExampleComponent).

 

BrowserAnimationsModule

 The first step in implementing an animation in Angular, as with most of Angular’s various functionalities, is that you need to import the corresponding module. In this case, you need to import the “BrowserAnimationsModule” into the module that you will be adding the animation to. In the ng-example case, the AnimationsExampleModule will look like this.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AnimationsExampleComponent } from './animations-example.component';
@NgModule({
  declarations: [AnimationsExampleComponent],
  imports: [CommonModule, BrowserAnimationsModule]
})
export class AnimationsExampleModule { }

 

Creating the Animation

 To create an animation using Angular’s API, you need to import the specific animation functions into the file in which you are writing the animations. Before we go about writing the animation function, I want to note how they are tied to a specific component.

An animation is added to a component’s metadata within the @Component() decorator. Similar to styleUrls, there is an “animations” property that can hold an array of animation “triggers”.

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

 

Now, just like you can write the template and styleUrls directly in the component decorator metadata, you can write your animation triggers directly in the metadata as well. However, for cleanliness, I prefer to generate a separate file for the animation trigger. This also will allow for re-use of the animation triggers in separate components.

So let’s create that separate file, I’m going to call it “toast-animation.ts”. Within that file, we will export a variable that implements the “AnimationTriggerMetadata” interface.

trigger()

The trigger() function instantiates and returns an instance of the AnimationTriggerMetadata interface. Per the angular.io docs, the trigger function’s signature looks like this:

trigger(nameOfTrigger: string, definitions: AnimationMetadata[])

The “nameOfTrigger” is what will be used to associate an element with the trigger.

The “definitions” is an animation definition object, containing an array of state and transition declarations.

 

Implementing the trigger() in toast-animation.ts

 With that information, we can start to implement our trigger() in our animation file. The animation file looks like this:

import { trigger, AnimationTriggerMetadata } from '@angular/animations';

export const toastAnimation: AnimationTriggerMetadata = 
   trigger('toast',
            [
              //Animation definition
            ]
);

 

Here we exported a constant named “toastAnimation” that implements the “AnimationTriggerMetadata” interface. It’s set equal to a “trigger” function, that we have named “toast”. Next, we need to fill out the animation definition.

 

Animation definition with state, style, transition, and animate

 For this example, we are going to implement an animation using those four functions. There are additional functions that can be used, but this is all that is necessary for this example.

 

state() and style()

The state function is used to “define different states to call at the end of each transition”. It takes a unique name, and then a style definition. The style definition is a function used to define a set of styles associated with that particular state. For our toast definition we will need a definition for “show” and “hide”. Our style’s and state’s will look like this:

state('show', style({bottom: '40px'})),
state('hide', style({bottom: '-100%'})),

 

These styles will be applied to a <div> with a “fixed” position. Meaning the <div> will move to off the screen on “hide”, and to 40px from the bottom on “show”.

 

transition() and animate()

 As is, we will be able to transition from “hide” to “show. However, without a transition() definition, the style changes will happen instantaneously. That doesn’t really give us the desired toast effect. So we need to add a transition() definition. The transition() function takes two arguments. First is an expression defining the direction of the transition between states (like hide to show). The second argument is the animate() function defines the “length, delay, and easing of a transition”.

We will need to define two transitions. One for “show to hide” and one for “hide to show” states. Our two transitions will look like this:

transition('hide => show', animate('1s ease')),
transition('show => hide', animate('1s ease'))

The animate() function takes a string defined in three parts: animate(‘duration delay easing’)

 

Putting it all together

 Our trigger() function will look like this:

import { trigger, state, style, animate, transition, AnimationTriggerMetadata } from '@angular/animations';

export const toastAnimation: AnimationTriggerMetadata = trigger('toast',
    [
        state('show', style({
            bottom: '40px'
        })),
        state('hide', style({
            bottom: '-100%'
        })),
        transition('hide => show', animate('1s ease')),
        transition('show => hide', animate('1s ease'))
    ]
);

 

Component Implementation

 Implementing the transition in the component is pretty straight forward. First, we need to add the trigger() into the animations array in the component’s metadata:

import { toastAnimation } from './toast-animation';

@Component({
  selector: 'app-animations-example',
  templateUrl: './animations-example.component.html',
  styleUrls: ['./animations-example.component.css'],
  animations: [toastAnimation]
})

 

To demonstrate the animation, I added a button to the page that will toggle a component variable that holds the state of the toasty div. The component then also have the toasty div. The component template will look like this:

<div class="d-flex w-100 h-100 justify-content-center align-items-center">
  <button class="btn btn-primary" (click)="toggleToast()">Animate Toast!</button>
</div>

<div class="card toasty" [@toast]="toastState">
  <div class="card-body">
    Hey, I'm a piece of toast!
  </div>
</div>

 

All of the styling classes are taken from bootstrap with the exception of “toasty”. The important part of that class is that it sets, “position: fixed”, and then it has some additional aesthetic styling. These styles are necessary for the toasty to work, but are not necessary for all animations. You may have to get creative with the styling of the elements that you wish to animate.

Now the important part to look at is the [@toast]=”toastState” on the toasty div. If you recall, “toast” is the name of the trigger we created. “toastState” is our component variable that we change from “hide” to “show” when “toggleToast()” is called by the button. That function looks like this and should be added to the component’s .ts file:

toggleToast() {
  if (this.toastState == 'hide') {
    this.toastState = 'show';
  } else {
    this.toastState = 'hide';
  }
}

 

With that, you should be able to run the example and click the button to show and hide the toast!

 

Final Notes

This has been an introductory example of using some of the basic functionality of Angular’s animation API. I definitely encourage you to check out their animation documentation for more information and additional functionality.

Additionally, if you want a working example to play with, all of this code put together is in my ng-example repository on GitHub. Thanks for reading, and leave any questions in the comments!