Home > Enterprise >  Angular animation programmatically, how to call animation builder before ngOnDestroy for leave anima
Angular animation programmatically, how to call animation builder before ngOnDestroy for leave anima

Time:11-01

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();
    });
}
  • Related