let\'s say I have 2 routed components and two Routerlinks in the fixed navbar to route them. I want them to slide in from the right when I click the Routerlinks.
I d
With Angular 4.1 it is now possible to create specific route animations. This is different from triggering an animation when a component is displayed because it will let you animate the entering/leaving component at the same time for a smooth transition, and let you modify the transition depending on which component is coming or going. That means you can do complex transitions like slide a component in from the right if you're drilling down into content, and slide it in from the left if you're entering it via a 'back' button from another component.
First, annotate your router outlet like so (eg. app.component.html
):
<div class="page" [@routerAnimations]="prepareRouteTransition(outlet)">
<router-outlet #outlet="outlet"></router-outlet>
</div>
Implement the prepareRouteTransition(outlet)
function in the corresponding component definition (e.g. app.component.js
).
prepareRouteTransition(outlet) {
const animation = outlet.activatedRouteData['animation'] || {};
return animation['value'] || null;
}
Define your animations (e.g. app.component.js
):
const slideLeft = [
query(':leave', style({ position: 'absolute', left: 0, right: 0 ,transform: 'translate3d(0%,0,0)' }), {optional:true}),
query(':enter', style({ position: 'absolute', left: 0, right: 0, transform: 'translate3d(-100%,0,0)' }), {optional:true}),
group([
query(':leave', group([
animate('500ms cubic-bezier(.35,0,.25,1)', style({ transform: 'translate3d(100%,0,0)' })), // y: '-100%'
]), {optional:true}),
query(':enter', group([
animate('500ms cubic-bezier(.35,0,.25,1)', style({ transform: 'translate3d(0%,0,0)' })),
]), {optional:true})
])
]
const slideRight = [
query(':leave', style({ position: 'absolute', left: 0, right: 0 , transform: 'translate3d(0%,0,0)'}), {optional:true}),
query(':enter', style({ position: 'absolute', left: 0, right: 0, transform: 'translate3d(100%,0,0)'}), {optional:true}),
group([
query(':leave', group([
animate('500ms cubic-bezier(.35,0,.25,1)', style({ transform: 'translate3d(-100%,0,0)' })), // y: '-100%'
]), {optional:true}),
query(':enter', group([
animate('500ms cubic-bezier(.35,0,.25,1)', style({ transform: 'translate3d(0%,0,0)' })),
]), {optional:true})
])
]
Add the animation metadata to your route definitions (e.g. app.routing.ts
):
const routes: Routes = [
{
path: 'products',
component: ProductsComponent,
data: {
animation: {
value: 'products',
}
}
},
{
path: 'products/:id',
component: ProductDetailComponent,
data: {
animation: {
value: 'product-detail',
}
}
}
Finally, register a 'routerAnimations' animation trigger on your component with the animations and route metadata you defined (e.g. app.component.js
):
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [
trigger('routerAnimations', [
transition('products => product-detail', slideRight),
transition('product-detail => products', slideLeft),
])
]
})
Don't forget to polyfill the Web Animation API to target old browsers
Matias Niemela talks more about route animations at ng-conf here (with a demo): https://youtu.be/Oh9wj-1p2BM?t=12m21s
His presentation code: https://github.com/matsko/ng4-animations-preview
In terms of sliding in it is quite straightforward.
You can reference to the Official Angular 2 Animate docs.
You can also check out this Plunker I did for a simple showcase, using the new router v3
Bear in mind that I am struggling to figure out how to actually have the leave/exit/void transitions when the triggered element is about to be destroyed from the view.
I opened another thread in Angular 2 Animate - No visible effect of the '* => void' transition when changing routes/components to try to figure out how to make router take notice of the leaving animation/transition time.
@Component({
selector: 'home',
directives: [ROUTER_DIRECTIVES],
template: `
<div @flyInOut="'active'" class="radibre">
</div>
`,
styles: ['.radibre { width: 200px; height: 100px; background: red; }'],
animations: [
trigger('flyInOut', [
state('in', style({transform: 'translateX(0)'})),
transition('void => *', [
style({transform: 'translateX(-100%)'}),
animate(100)
]),
transition('* => void', [
animate(100, style({transform: 'translateX(100%)'}))
])
])
]
})
export class Home {
constructor() { }
}
@Component({
selector: 'page',
template: `
<div @testingBottom="'active'" class="page"></div>`,
styles: ['.page { width: 300px; height: 50px; background: green; }'],
animations: [
trigger('testingBottom', [
state('active', style({transform: 'scale(1)'})),
transition('void => *', [
style({transform: 'scale(0)'}),
animate(100)
]),
transition('* => void', [
animate(100, style({transform: 'scale(0)'}))
])
])
]
})