Search code examples
angularangular-animations

Need to pause the Carousel animation regularly and call a function


I have a Carousel animation:

enter image description here

which is working fine but I need to pause it after a duration and call a function.

As soon as the cards change their position, I want to pause it, call my function, and as soon as the execution of that function is over, again restart the animation. And I want to do this indefinitely.

I am creating my animation using AnimationBuilder's build() function.

I tried to make use of AnimationPlayer's pause() and restart() methods but was not able to set them properly.

Here's Stackblitz link.

Here's my code:

.ts: animateCarousel() contains the animation definition.

  @ViewChildren("card") items: QueryList<ElementRef>;
  @ViewChild("container") container: ElementRef;
  @ViewChild("dataInit") dataInit: ElementRef;
  rect: any;
  private player: AnimationPlayer;
  timing = "2000ms ease-in-out";
  selectedIndex = 0;
  rectElement: any;
  order: number[] = this.data.map((_x, i) => this.data.length - i);
  constructor(private builder: AnimationBuilder) {}

  ngAfterViewInit() {
    this.calculateDimensions();
    this.animateCarousel();
  }

  calculateDimensions() {
    this.rectElement = this.items.first.nativeElement.getBoundingClientRect();
    const rect = this.dataInit.nativeElement.getBoundingClientRect();
    const rectContainer = this.container.nativeElement.getBoundingClientRect();

    this.rect = {};
    this.rect.height = rectContainer.height - rect.y;
    this.rect.y = rect.y;
    this.rect.width = rectContainer.width - this.rectElement.width;
  }

  animateCarousel() {
    this.items.forEach((item: ElementRef, index: number) => {
      this.order[index] = this.items.length - ((index + this.selectedIndex) % this.items.length);
      const itemStyle = this.items.length > 5 ? this.getStyle2(index) : this.getStyle(index);

      const myAnimation = this.builder.build([
        animate(this.timing, style(itemStyle))
      ]);

      this.player = myAnimation.create(item.nativeElement);

      if (index == 0)
        this.player.onDone(() => {
          this.calculateDimensions();
          this.selectedIndex =
            (this.selectedIndex + this.items.length - 1) % this.items.length;

          this.animateCarousel();
        });

      this.player.play();
    });
  }

.html:

<div #container class="container">

    <div class="header">
        A Simple Carousel
    </div>
    <div #dataInit class="data"></div>
    <div #card class="cards" [ngStyle]="{'z-index':order[i]}" [style.visibility]="order[i]>=2 && order[i]<=data.length-5?'collapse':null" *ngFor="let item of data; let i = index;">
            <div class="name">{{ item.name }}</div>
            <div class="age">{{ item.age }}</div>
    </div>
</div>

Solution

  • take a look to the animateFunction, when you write

    if (index == 0){
       this.calculateDimensions();
              this.selectedIndex =
                (this.selectedIndex + this.items.length - 1) % this.items.length;
    
              this.animateCarousel();
    }
    

    You're saying that the animate go on. You can get out the if in a function like,e.g.

    executeAction()
    {
       console.log(this.data[this.selectedIndex])
       //you,e.g. subscribe to a service to getData, and after subscribe
       //execute the function
       this.dataService.getData().subscribe(res=>{
          this.calculateDimensions();
          this.selectedIndex =
            (this.selectedIndex + this.items.length - 1) % this.items.length;
    
          this.animateCarousel();
       })
    }
    

    Then transform the "if" to some like

     if (index == 0)
        this.player.onDone(() => {
          this.executeAction()
        });
    

    You can also remove fully the "if" and has in a button

    <button> (click)="executeAction()">next</button>
    

    In this forked stackblitz I use a "timer" to simulate the service.getData().subscribe