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?
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 {
...