Reputation: 173
In my project, I have the following:
slideInOut.ts
module import { trigger, state, animate, transition, style } from '@angular/animations';
export const slideInOut = trigger('slideInOut', [
state('*', style({
transform: 'translateX(0)'
})),
// route 'enter' transition
transition(':enter', [
style({
transform: 'translateX(100%)'
}),
animate('.3s ease-in-out', style({
transform: 'translateX(0)'
}))
]),
// route 'leave' transition
transition(':leave', [
animate('.3s ease-in-out', style({
transform: 'translateX(100%)'
}))
])
]);
home.component.ts
import { Component } from '@angular/core';
import { slideInOut } from '../../animations/slideInOut';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
animations: [
slideInOut
],
styleUrls: ['./home.component.css']
})
export class HomeComponent {
constructor() {}
}
home.component.html
<div @slideInOut>
<button [routerLink]="['', { outlets: {'aux': null} }]">Test</button>
</div>
For some reason, the leave animation doesn't trigger. My component slides in correctly, but not out. It sits for .3s
and then disappears. I've tried multiple CSS properties instead of transform and the same thing happens. I've also tried replacing :leave
with * => *
and * => void
just to be sure. Any ideas? Thanks!
Upvotes: 2
Views: 5066
Reputation: 4917
The reason your :leave animation does not happen is because the route has changed and so did you "canvas"/component.
The :enter trigger animates because your animation is defined within your now active route, and when you visit it the "canvas" is there from the beginning.
Basically you need to think outside the box in our case <router-outlet></router-outlet>
One way you can do it is is to wrap the router-outlet in a div container that will be animated, and the trigger for that animation will be route changes, you can listen for these in a bunch of ways.
Firstly I've added data to our routes to differentiate them:
const routes: Routes = [
{ path: 'home', component: HomeComponent, data: { state: 'home' } },
{ path: 'about', component: AboutComponent, data: { state: 'about' } },
];
We can then wrap the router-outlet in app.component.html
like this:
<main [@routerTransition]="getState(o)">
<router-outlet #o="outlet"></router-outlet>
</main>
The getState() method in app.component.ts
handles the route change detection and triggers the animations:
getState(outlet) {
// Changing the activatedRouteData.state triggers the animation
return outlet.activatedRouteData.state;
}
And at the end we have the animation simply attached to the app component's decorator:
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
animations: [
trigger('routerTransition', [
transition('* <=> *', [
query(':enter, :leave', style({ position: 'fixed', width:'100%' })),
group([
query(':enter', [
style({ transform: 'translateX(100%)' }),
animate('0.5s ease-in-out', style({ transform: 'translateX(0%)' }))
]),
query(':leave', [
style({ transform: 'translateX(0%)' }),
animate('0.5s ease-in-out', style({ transform: 'translateX(-100%)' }))]),
])
])
])
],
})
You can check out this in practice here:
Upvotes: 3