In the html I have ngIf to control show or destroy drawer component. I would like to use AnimationBuilder to call my animation dynamically for the drawer. SO I used animation builder in the parent component(app component), it works well when applying slideIn animation to drawer. But I want to apply slideOut animation when drawer component is moved away from DOM. It doesn't work because ngOnDestroy is called before my animation is finised.
Note, I know :leave
:enter
probably will work, But I want to know if this can work with AnimationBuilder specifically. Problem is I don't know how to play animation just before ngOnDestroy.
Here is the html with ngIf to control show or destroy drawer
<app-drawer #drawer *ngIf="showDrawer"></app-drawer>
My app-component
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit, OnDestroy {
title = 'angular-test';
showDrawer = false;
// @ts-ignore
player: AnimationPlayer;
// @ts-ignore
@ViewChild('drawer', { read: ElementRef }) drawer: ElementRef;
constructor(
private animationBuilder: AnimationBuilder,
private cdr: ChangeDetectorRef
) {}
toggleDrawer(): void {
this.showDrawer = !this.showDrawer;
this.runSlideAnimation(this.showDrawer);
}
runSlideAnimation(showDrawer: boolean): void {
if (showDrawer) {
// to make sure element is on dom by ngIf change before I apply animation
this.cdr.detectChanges();
}
if (this.player) {
this.player.destroy();
}
const factory = this.animationBuilder.build(
showDrawer ? slideInAnimation : slideOutAnimation
);
this.player = factory.create(this.drawer.nativeElement);
this.player.play();
// My thoughts was manually update dom when slideout animation finish so angular will call
// ngOndestroy after my animation is done. it didn't work
this.player.onDone(() => {
this.cdr.detectChanges();
});
}
ngOnInit(): void {
console.log('init');
}
ngOnDestroy(): void {
if (this.player) {
this.player.destroy();
}
console.log('destroy');
}
get slideInAnimation() {
return [
style({ opacity: 0, transform: 'translateX(100%)' }),
animate('600ms', style({ opacity: 1, transform: 'translateX(0)' })),
];
}
get slideOutAnimation() {
return [
style({ opacity: 1, transform: 'translateX(0)' }),
animate('900ms', style({ opacity: 0, transform: 'translateX(100%)' })),
];
}
}
CodePudding user response:
I imagine that you can use a setter
_showDrawer:boolean
get showDrawer(){
return this._showDrawer;
}
set showDrawer(value){
if (!value){
this.runSlideAnimation(value,true)
}
else
this._showDrawer=value
}
And your function runSlideAnimation
runSlideAnimation(showDrawer: boolean,forceDestroy:boolean=false){
...
this.player.onDone(() => {
if (forceDestroy)
this._showDrawer=false
this.cdr.detectChanges();
});
}