Angular Router Animations: the tricky bits

Most articles & tutorials on this topic cover the same simple scenario. This one is different.

Tomek Sułkowski
frontend.coach
5 min readApr 25, 2018

--

What example am I referring to? The one in which an app:

  • routes between different components
    (e.g. HomeComponent to ContactComponent to SettingsComponent)
  • and animates in one direction only, like this:
“Why does it always move left?”

In this article our example will be able to handle changes on a route parameter and will rock the left and right animation 💪. So strap in, we’re gonna talk about some new, possibly advanced stuff here!

I’ve put the completed code on Github and you can see the working demo on StackBlitz.

Problem 1: Route definition

“Oooh, it’s the same component!”

It’s not uncommon to have a nested routes with params, right?

E.g. you have a list of items, select an item and see a page with the item’s details. From that page you may want to go directly to the next or previous item’s page.

The routing definition can look like this:

app-routing.module.ts

Next we will add the animation definition to the ItemsComponent’s decorator and a getState method that we’ll use to obtain different values for animation trigger:

items.component.ts

With a template looking like this:

items.component.html

we should now have animating page changes. Except we don’t.

What is the issue here? The transition is defined for :enter and :leave queries, which means it will run whenever a component within the query will be created or destroyed.

But when the path change happens within the same route entry, e.g. we move directly from domain.com/items/4 to domain.com/items/5 Angular does not create a new component but instead reuses the existing one. See it for yourself and put a console.log in the constructor —if only route param changes the component will not be constructed again.

This feature is called RouteReuseStrategy and, you’ve guessed it, we can configure it.

app-routing.module.ts

RouteReuseStrategy configuration

To change the default behaviour, we need to create a special class that should implement Angular’s RouteReuseStrategy interface and then provide it into our application:

And that’s it — first problem solved 😎 (and I will not admit how long it took me to come up with this solution)

Problem 2: Animation direction

“So I can change transition params after I have defined it?!”

Let’s create a service that will track changes of ItemComponent route:

items-routing.service.ts

Now in our ItemComponent we will emit an index of the item on the items list each time the component loads (i.e. we change the route)

Note: the param will be a string so we need to cast it to a number for later calculations.

And finally we will use this observable in the parent ItemsComponent to calculate all the data we need for our transition.
For this one I’ve added line numbers so we can go over it in more details:

items.componen.ts

line #4: pairwise operator (from rxjs/operators) changes the resulting stream so that instead of only emitting a new value, it now emits last 2 values.
line #3: We actually can’t wait for 2 values, we will already need a pair emitted on the first itemChange, so startWith(0) operator gives us something (value 0) to pair our first value with.
line #5: The pair is emitted as an array, so we destructure it to descriptive variable names.
lines #6-10: We will pass this whole object as Angular trigger’s value in the template.
lines #7-10: The params property defines, well, parameters that we can use in our animation definition. We can name them however we want. I hope you can already see the logic here:

Knowing that 0 is the offset of a page that is visible on the screen, if we go from a bigger index to a smaller one (prev > curr) we want our page to enter the screen from the right to the left (+100 -> 0) and leave it also to the left (0 -> -100).
Otherwise we move in the opposite way.

Our updated template now uses the routeTrigger$ observable like this:

Notice that with this new implementation we don’t need to user `outletRef` now.

And as for the animation, we only need to update translateX so that they use our defined params:

With all our changes we can now enjoy a nicer and a bit more intuitive experience when using our app:

See the code and working demo here: https://stackblitz.com/edit/angular-child-route-animation

Did you learn something new? If so, you can:

→ clap 👏 button below️ so more people can see this
follow me on Twitter (@sulco) so you won’t miss future posts!

--

--