javascriptcssangulartypescriptangular-animations

How to wait for Angular to initialize before triggering an animation?


In this demo the dashOffset property is used to trigger the dash-offset animation.

So for example if we enter a new percentage in the input field we see the animation is triggered. The code that updates the dashOffset state looks like this:

  @Input({ transform: (p: string) => parseInt(p) })
  set percentage(p: number) {
    this.percentageState = p;
    if (!this.firstAnimation) {
      if (!!p) {
        this.dashOffset = this.calculateDashOffset(this.percentageState);
      } else {
        this.dashOffset = undefined;
      }
    }

If it's not the first animation, then the dashOffset state is calculated and this triggers the animation.

If it is the firstAnimation then dashOffset state is set in ngAfterViewInit like this:

  ngAfterViewInit() {
    if (this.firstAnimation) {
      this.dashOffset = this.calculateDashOffset(this.percentageState);
      this.firstAnimation = false;
      console.log(`The dash offset is ${this.dashOffset}`);
    }
  }

However this does not trigger the animation.

Where in the component lifecycle should we initialize an animation trigger in order to trigger the first animation?


Solution

  • Some things you can do:

    First: You set changeDetection: ChangeDetectionStrategy.OnPush, so you need to push any changes. Do it like this:

    svg-cicle.component.ts

      constructor(private ngz: NgZone, private changeRef: ChangeDetectorRef) {}
    
      private firstAnimation: boolean = true;
      ngAfterViewInit() {
        if (this.firstAnimation) {
              this.dashOffset = this.calculateDashOffset(this.percentageState);
              this.firstAnimation = false;
              this.changeRef.detectChanges();
        }
      }
    

    Then easily set the percent in the main component, which gives the data to the cicle itself:

    main.ts

     ngOnInit() {
        this.control.valueChanges.subscribe((percent: any) => {
          console.log(percent);
          percent = parseInt(percent);
    
          percent = !!percent ? percent : 100;
          percent = isNaN(percent) ? 100 : percent;
          percent = percent < 0 ? 0 : percent;
          percent - percent > 100 ? 100 : percent;
          this.percentage = percent;
        });
    
        setTimeout(() => {
          this.percentage = 20;
        },1)
      }
    

    The setTimeout add the change into a new render frame and the animation works on start, and on every changing.