How can I do a crossfade with angular animate and ngFor?

436 Views Asked by At

I'm triggering an animation when I update the collection I pass into *ngFor:

//JS
state : string = 'a';
colors = {
  a: ['red','blue','green','yellow'],
  b: ['orange']
}

public onClick (){
  this.state = this.state === 'a' ? 'b' : 'a';
}

//HTML
<div *ngFor="let color of colors[state]" 
   [@animationState]="state" 
   (click)="onClick()">
     {{color}}
</div>

The problem: While the animation is happening, colors from both a and b display, which makes the animation jerky.

I've tried:

  • setting transform: scale(0) or display:none before the void => * animation begins
  • delaying the void => * animation by the duration of the * => void animation

I want: to smoothly fade and/or slide out my existing content before (or while) the new content fades/slides in.

Here's a plunkr that demonstrates the problem: https://plnkr.co/edit/IDE6q6lJ84QI2Zirvn4P?p=preview

1

There are 1 best solutions below

0
On BEST ANSWER

I managed to make it work, but it feels like a hack. Instead of setting the ngFor collection to the new value immediately, I

  1. store the new value in a temp variable
  2. set the ngFor collection to an empty collection
  3. when the animation to an empty collection completes, update the collection to the value stored in the temp variable

This triggers two animations instead of one, but seems to work well.

//JS
state : string = 'a';
temp : string;
colors = {
  a: ['red','blue','green','yellow'],
  b: ['orange'],
  empty: []
}

public onClick (){
  this.temp = this.state === 'a' ? 'b' : 'a';
  this.state = 'empty'
}

public animationComplete(){
  if(this.temp){
    this.state = this.temp;
    this.temp = undefined;
  }
}

//HTML
<div *ngFor="let color of colors[state]" 
   [@animationState]="state" 
   (@animationState.done)="animationComplete()"
   (click)="onClick()">
     {{color}}
</div>