Reputation: 1647
I have read this article about Router transition Animations for Angular:
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.
Upvotes: 12
Views: 11798
Reputation: 899
Great solution from Michal.S. So I can use this also without Routechange but also on your own tab component.
If you have a custom tab control you can do it like this:
Step 1: Add the animation above
const left = [
query(':enter, :leave', style({ position: 'absolute', width: '100%' }), { optional: true }), // or fixed
group([
query(':enter', [style({ transform: 'translateX(-100%)' }), animate('.4s ease-out', style({ transform: 'translateX(0%)' }))], {
optional: true,
}),
query(':leave', [style({ transform: 'translateX(0%)' }), animate('.4s ease-out', style({ transform: 'translateX(100%)' }))], {
optional: true,
}),
]),
];
const right = [
query(':enter, :leave', style({ position: 'absolute', width: '100%' }), { optional: true }),
group([
query(':enter', [style({ transform: 'translateX(100%)' }), animate('.4s ease-out', style({ transform: 'translateX(0%)' }))], {
optional: true,
}),
query(':leave', [style({ transform: 'translateX(0%)' }), animate('.4s ease-out', style({ transform: 'translateX(-100%)' }))], {
optional: true,
}),
]),
];
Step 2: In the template add the trigger to the container of the animation items. Relative or flex positioned.
<div [@animStep]="currentStep">
<app-step1 *ngIf=“currentStep === 1”></app-step1>
<app-step2 *ngIf=“currentStep === 2”></app-step2>
<app-step3 *ngIf=“currentStep === 3”></app-step3>
</div>
Step 3: Add the animation inside the Component decorator
// component
animations: [
trigger('animStep', [
transition(':increment', right),
transition(':decrement', left),
]),
],
Step 3: Trigger change of the value
currentStep += 1;
Upvotes: 0
Reputation: 531
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,
}),
]),
];
Upvotes: 11
Reputation: 1647
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.
Upvotes: 3