javascriptangularcss-transitionsangular-transitions

Angular 5 and transition only in 'new' items


My component's template renders a list:

<div class="row">
  <div *ngFor="let m of activeModules" [@enterAnimation]>
    {{ m.name }}
  </div>
</div>

The component animates it

@Component({
  selector: 'app-client-detail',
  templateUrl: './client-detail.component.html',
  styleUrls: ['./client-detail.component.scss'],
  animations: [

    trigger(
      'enterAnimation', [
        transition(':enter', [
          style({ opacity: 0 }),
          animate('1000ms', style({ opacity: 1}))
        ]),
        transition(':leave', [
          style({ opacity: 1 }),
          animate('1000ms', style({ opacity: 0}))
        ])
      ]
    )
  ]
})
export class ClientDetailComponent implements OnInit {
   activeModules = [{ name: 'modulo 1'}, { name: 'modulo 2'}];
}

This works fine, the 'divs' have the transition from the opacity. If I do something like this:

ngOnInit() {
  Observable.timer(2000).subscribe(() => {
    this.activeModules =  [{ name: 'modulo 1'}, { name: 'modulo 3'}, { name: 'modulo 2'}];
}

the activeModules' array is updated and the templates renders again the list with the transition. My problem is that I need only the 'new' items from the array (in this case, the one in the middle) to have the transition. Is it possible?


Solution

  • Sure, you just need to push your item instead of creating your array again.

    Let's make a function for that :

    pushAt(arr, index, item) {
      arr.splice(index, 0, item); 
    }
    

    Now you can just

    ngOnInit() {
      Observable.timer(2000).subscribe(() => this.pushAt(this.activeModules, 1, { name: 'Modulo 2' }));
    }
    

    EDIT maybe you can try with a custom trackby function :

    customTrackBy(index, item) { return index; }
    

    In your HTML

    <div *ngFor="let m of activeModules; trackBy: customTrackBy;" [@enterAnimation]>