I have read this article about Router transition Animations for Angular:
https://medium.com/google-developer-experts/angular-supercharge-your-router-transitions-using-new-animation-features-v4-3-3eb341ede6c8
And:
Angular 2 "slide in animation" of a routed component
However, this is too static. I want it to slide left and right depending on the order of the tab.
Is it possible to create router animations for this? Example of what I mean is below:
https://material.angular.io/components/tabs/examples
Look how it slides BOTH left and right very naturally depending on what tab you are on.
This has to be dynamic, because the tabs will be added at runtime.
In Angular, transition states can be defined explicitly through the state() function, or using the predefined * (wildcard) and void states.
Transitions between two states take place so that we can build simple animations between two states driven by a model attribute. Transition basically means navigating from the current state to a new state. In angular, the transition is an animation-specific function which is used in angular's animation DSL language.
The Angular router comes with high-level animation functions that let you animate the transitions between views when a route changes. To produce an animation sequence when switching between routes, you need to define nested animation sequences.
The easing value controls how the animation accelerates and decelerates during its runtime. Value is one of ease , ease-in , ease-out , ease-in-out , or a cubic-bezier() function call. If not supplied, no easing is applied.
I have managed to get this to work by "faking" the state it is in.
In the component.html
:
<div [@animRoutes]="pageState">
<router-outlet></router-outlet>
</div>
pageState
is a variable in the component.ts
file.
Whenever I click on a tab which I want to go right, I will set pageState
to right
, and same for left
, and let Angular take over the rest.
Note: You have to create a right
and right1
state as a hack, because Angular currently does not support right => right
state transitions!! Same applies to left
of course.
My @Component
annotation is below:
@Component({
selector: 'app-workspace-container',
templateUrl: './workspace-container.component.html',
styleUrls: ['./workspace-container.component.scss'],
animations: [
trigger('animRoutes', [
transition('* => right', right),
transition('* => left', left),
transition('* => right1', right),
transition('* => left1', left),
]),
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
Where left
, left1
, right
, right1
are:
const left = [
query(':enter, :leave', style({ position: 'fixed', width: '100%' }), { optional: true }),
group([
query(':enter', [style({ transform: 'translateX(-100%)' }), animate('.3s ease-out', style({ transform: 'translateX(0%)' }))], {
optional: true,
}),
query(':leave', [style({ transform: 'translateX(0%)' }), animate('.3s ease-out', style({ transform: 'translateX(100%)' }))], {
optional: true,
}),
]),
];
const right = [
query(':enter, :leave', style({ position: 'fixed', width: '100%' }), { optional: true }),
group([
query(':enter', [style({ transform: 'translateX(100%)' }), animate('.3s ease-out', style({ transform: 'translateX(0%)' }))], {
optional: true,
}),
query(':leave', [style({ transform: 'translateX(0%)' }), animate('.3s ease-out', style({ transform: 'translateX(-100%)' }))], {
optional: true,
}),
]),
];
TL;DR: Make the state you are going to into a variable, so you can dynamically set the state which you wish you are going to.
Today things are a bit simpler because new animation aliases exist as :increment and :decrement. Aliases have been introduced in Angular 5.
So my modified solution is:
@Component({
selector: 'app-workspace-container',
templateUrl: './workspace-container.component.html',
styleUrls: ['./workspace-container.component.scss'],
animations: [
trigger('animRoutes', [
transition(':increment', right),
transition(':decrement', left),
]),
],
})
export class ComponentContainingRouterOutlet implements OnDestroy, OnInit {
//... ngOnInit,ngOnDestroy
constructor( private route: ActivatedRoute ) { }
animationState: number;
onActivate($event) {
this.animationState = this.route.firstChild.snapshot.data['routeIdx'];
}
}
Call animation at router-outlet position:
<div [@animRoutes]="animationState">
<router-outlet (activate)="onActivate($event)"></router-outlet>
</div>
modify routes definition as example, look at data: { routeIdx: X }
:
const routes: Routes = [
{
path: 'routeOne',
component: ComponentOne,
data: { routeIdx: 0 }
},
{
path: 'routeTwo',
component: ComponentTwo,
data: { routeIdx: 1}
},
{
path: 'routeThree',
component: ComponentThree,
data: { routeIdx: 2 }
},
{
path: 'routeFour',
component: ComponentFour,
data: { routeIdx: 3 }
},
{
path: '',
redirectTo: 'routeOne',
pathMatch: 'full'
}
]
And transitions are the same as in Dolan's post:
const left = [
query(':enter, :leave', style({ position: 'fixed', width: '100%' }), { optional: true }),
group([
query(':enter', [style({ transform: 'translateX(-100%)' }), animate('.3s ease-out', style({ transform: 'translateX(0%)' }))], {
optional: true,
}),
query(':leave', [style({ transform: 'translateX(0%)' }), animate('.3s ease-out', style({ transform: 'translateX(100%)' }))], {
optional: true,
}),
]),
];
const right = [
query(':enter, :leave', style({ position: 'fixed', width: '100%' }), { optional: true }),
group([
query(':enter', [style({ transform: 'translateX(100%)' }), animate('.3s ease-out', style({ transform: 'translateX(0%)' }))], {
optional: true,
}),
query(':leave', [style({ transform: 'translateX(0%)' }), animate('.3s ease-out', style({ transform: 'translateX(-100%)' }))], {
optional: true,
}),
]),
];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With