Reputation: 101
I have a test app build with angular 2, I have successfully applied one animation between route change
state('default', style({
opacity: 1,
transform: 'scale(1) translateY(0)'
})),
transition('void <=> default', [
style({ opacity: 0, transform: 'scale(.9) translateY(-20px)' }),
animate('.2s')
])
But I also want a different animation when a list page change to an item page, like click a hero inside a hero-list, so I did this
state('childActivate', style({
opacity: 1,
transform: 'scale(1) translateY(0)'
})),
transition('childActivate => void', [
animate('1.2s', style({
transform: 'scale(0.9) translateY(-120px)',
opacity: 0
}))
])
I tried to set the state to 'childActivated' after i click on an item and before navigation:
onHeroSelected(heroEvent: Hero) {
this.animState = "childActivate";
this.router.navigate(['/hero-detail', heroEvent.id]);
}
but has no effect.
How can I get multiple animations between route?
Upvotes: 3
Views: 1326
Reputation: 5572
Setting the state to "childActivate" has no effect, because the component is being destroyed within the next change detection step, so state switches to void instead.
This is how i solved this issue: I delay the route change by 1 further change detection cycle. I use a CanDeactivate Guard for this, which listens for a promise to resolve.
Check out my plnkr: https://embed.plnkr.co/cOeDfXCetaYuXFaZ7WeO/
Within route definitions i add:
canDeactivate: [CanDeactivateAfterChangeDetectionGuard]
This is the CanDeactivate Guard:
@Injectable()
class CanDeactivateAfterChangeDetectionGuard implements CanDeactivate<WaitForChangeDetection> {
canDeactivate(component: WaitForChangeDetection): Promise<boolean> {
return component.waitForChangeDetection();
}
}
which works with any component implementing this interface:
declare abstract class WaitForChangeDetection {
abstract waitForChangeDetection(): Promise<boolean>;
}
I created a base component with a default implementation of this interface
@Component({})
class WaitForChangeDetectionImpl implements AfterViewChecked, WaitForChangeDetection {
constructor(private cdRef: ChangeDetectorRef){
this.viewChecked$ = new Subject<void>();
}
viewChecked$: Subject<void>;
waitForChangeDetection(): Promise<boolean>{
this.cdRef.detectChanges();
return new Promise((resolve) => this.viewChecked$.subscribe(() => resolve(true)));
}
ngAfterViewChecked(){
this.viewChecked$.next();
}
}
So you can extend this component to provide the functionality to work with the guard for any component.
@Component({})
class ComponentA extends WaitForChangeDetectionImpl {
...
Upvotes: 1