Getting started with programmatic animations using the Angular Animations API

Stefan Peshikj
Web Factory LLC
Published in
7 min readMay 29, 2020

The @angular/animations package is a powerful tool that you can utilize to your advantage in creating great experiences for your users. A simple animation like fade in or fade out may prove to be super effective in upgrading your applications. Adding simple animations like this does not take longer than 10 minutes of development time, but it helps you to keep your users on your website a lot longer!

This blog showcases a simple example of how you can use the AnimationBuilder to create programmatic and reusable animations. It is designed for beginners who are starting to learn how animations work in Angular and for people who are curious to try out creating animations programmatically.

We are going to start with the basics of how programmatic animations work in Angular, then we will actually see it in action through an example. The full code for this example can be found on Github.

Image of Angular logo on a blue background

Introduction

What is an animation sequence? Well, to put it simply, it’s a sequence of simple changes to one or more elements that results in a complex operation giving users the illusion of motion, where the HTML elements change over time. These changes can be color and position changes, the visibility of the element, border changes, and so on.

A combination of multiple changes to different elements can greatly improve the user’s experience but this is a task that shouldn’t be taken lightly since it will require multiple iterations over the animations because the timings need to be synced to perfection.

From my personal experience, I’ve had to build a complex sequence of animations which also included items like the header and footer, whilst animating a part of the screen, so the normal HTML animations were of no use since the animation context was in the current component and it had no access to the other components because it was way down in the application hierarchy.

This led me to search for new ways to use animations, so I needed to create complex logic in a programmatic way in order to select all the elements I needed to animate. Maybe you have the same problems, and this blog might help you start off creating your solution!

How do we achieve animations in Angular?

As I mentioned above, Angular gives you a powerful tool that allows you to animate the content on your screen and create a better user experience for your end-users. Usually, this is done by creating animations in your component and using it in the HTML, while controlling the flow of the animations using certain states that you tell Angular to watch out for.

But how can you control the animations in a more programmatic way? Well, the AnimationBuilder API is the right tool for the job.

In order to use animations in our project, you need to install the animations package @angular/animations. Then you need to import the BrowserAnimationsModule in our AppModule. In case you’re using Server Side Rendering (example: Angular Universal project), you also should import the NoopAnimationsModule to avoid having problems while rendering on the server-side. These modules provide the AnimationBuilder and everything associated with animations in an Angular project. Since you will be using the AnimationBuilder, you are going to be required to import the ‘web-animations-js’ package, which makes it available for use in IE/Edge or Safari.

Note: standard animation support without the AnimationBuilder does not require any polyfills as of Angular 6.0.

Angular defines the AnimationBuilder as an injectable service that produces an animation sequence programmatically within an Angular component or directive. Since it’s an injectable service, this means that we can easily inject its dependency into one of our components or services, and use it on demand. For this, Angular has provided a simple API for us in order to use this tool.

abstract class AnimationBuilder {    abstract build(animation: AnimationMetadata | AnimationMetadata[]): AnimationFactory;}

The AnimationBuilder’s job is to build a factory for producing a defined animation. The AnimationFactory can then instantiate an AnimationPlayer that you’ll use as an end result to start/pause/finish an animation. So in order for you to get to that point, you first need to provide the animation that you would like to use. A way for you to do this is to create a reusable animation using the animation function provided by the @angular/animations API.

function animation(steps: AnimationMetadata | AnimationMetadata[], options?: AnimationOptions | null): AnimationReferenceMetadata;

Here you also have the flexibility to provide a range of parameters to the animation, like controlling the timings, and other variables connected to the actual animation before it’s created.

export const someAnimation = animation([
group([
query('.some-element-selector', [
style({ opacity: '0' }),
animate('2s', style({ opacity: '1' }))
]),
query('.some-other-element-selector', [
style({ backgroundColor: 'red', height: '200px' }),
animate('2s', style({ backgroundColor: 'white', height: '*' }))
])
])
]);
Gif showcasing the animation sequence
Preview of the animation group

In this particular snippet, I grouped two items and animated them in parallel using the group. I then query the first item by his css class selector, I hide it instantly, and in the course of one second, I’m making it visible to the user. For the second item, I’m also querying it by its css selector, I start with some background-color and height, and in the course of 1 second, I assign a different background color and return the height of the item to it’s computed size.

After you’ve created the initial animation, it is trivial to create the AnimationFactory using the AnimationBuilder.

const animationFactory = this.animationBuilder.build([
useAnimation(someAnimation)
]);

After you’ve created the AnimationFactory, you should use its create(args) method and provide the element which will act as a root of the animation, along with options for the animation (example: timings, variables, and so on). When invoked, this method will return an AnimationPlayer.

Note: This provides us flexibility to animate any element we want, for example, we can use the document at a root level. This can be used if we want to control elements that are outside of the component that is calling the animation.

// We could use any element here, as long as it has the required 
// arguments and selectors needed to build the animation
this.animationPlayer = animationFactory.create(window.document);

NOTE: If you have a complex animation that queries sub-elements, you need to make sure that they exist in the current viewport because Angular may fail when you try to create the animation with an element that does not exist. It does not matter if you want to play the animation later or not, Angular still needs to have all the elements and make sure they exist when creating the animation. This is important for when you have some *ngIf checks, where you need to make sure that the element exists and the checks are valid.

The AnimationPlayer is an Interface that has a well-defined API that you can reference. The most important thing for you to know is that you can hook into the start/end of the animation, and provide callbacks that you want to execute when these events happen.

For example, maybe you would like to destroy the animation and stop referencing it once it has finished, and also invoke some other callback provided to your method.

// Example if someone gave us this callback to execute when the 
// animation finishes. For simplicity, here we will show it in the // same snippet. Reference the demo project for the full code
const someOnDoneCallback = () => {
console.log(‘Finished animating’);
};
this.animationPlayer.onDone(() => {
this.animationPlayer.destroy();
this.animationPlayer = null;
if (someOnDoneCallback) {
someOnDoneCallback();
}
});
this.animationPlayer.play();

In order for you to start the animation, you need to invoke the play() method on the AnimationPlayer.

One thing to note is that if you are in the process of animating, and the user decides to leave the screen, you should first finish and dispose of the animation before you destroy your current component. It’s worthy to note that when using the standard animations provided by Angular, they take care of that for you, which is quite convenient. However, in this scenario we should also make sure to clean up after ourselves.

Note: You should not try to dispose of the animation twice since you may end up with an error while referencing the timeline engine. You also should not try to finish an animation that is already destroyed, as it may result in an error as well.

One way of handling it is by referencing the animationPlayer in your component/service, and using the ngOnDestroy() block to finish up the animation.

ngOnDestroy(): void {
if (this.animationPlayer) {
this.animationPlayer.finish();
}
}

By invoking the finish method, we make sure that the animation will call it’s onDone() callback that we specified above, and we can also invoke some teardown logic there as well.

By invoking the finish method, you are making sure that the animation will call its onDone() callback that we specified above, and you can also invoke some teardown logic as well.

And that’s it! Good luck with creating your awesome animations :). You can find the example for this demo on Github.

What next?

There are a lot of resources covering animations and how you can use them in complex scenarios. Learning about web animations is really important and can be really rewarding in the long run. Here are some popular links which can help you while learning.

--

--

Stefan Peshikj
Web Factory LLC

Fullstack Engineer at Web Factory LLC | LinkedIn https://www.linkedin.com/in/peshou/. Passionate Software Developer who wants to know many things :).