2

I have a list of array items in an ngFor. I have a simple button the adds an an item to the array. I want to apply an animation to the items when they are added only but although this works, the group of list items already on the page gets the animation on page load. How can I limit the animation only to the newly added item? This is in Angular 10.

I made a stripped-down Stackblitz.

animations: [
    trigger("myTrigger", [
      state(
        "fadeInFlash",
        style({
          opacity: "1"
        })
      ),
      transition("void => *", [
        style({ opacity: "0", transform: "translateY(20px)" }),
        animate("500ms")
      ])
    ])
  ]
<p>
  <button (click)="addItem()">Add Item</button>
</p>

<ul>
  <li *ngFor="let item of items" [@myTrigger]='state'>{{item}}</li>
</ul>
Steve
  • 14,401
  • 35
  • 125
  • 230

1 Answers1

0

Here is the solution link of stackbliz to your problem I just used disabled attribute of Angular animation. If flag variable is true then animation will be disabled and if it is false then animation is enabled which we are doing after page init where all the content is loaded so that then the trigger of the animation will only work on push operation.

Stackbliz

Reference Link

ngAfterViewInit Reference link

Edit: To avoid console error ExpressionChangedAfterItHasBeenCheckedError please enable animation on add item as below. Even stackbliz code has been updated accordingly for reference.

    addItem() {
        if (this.flag) {
          // Enabling Animation
          this.flag = !this.flag;
        }
        this.items.push("another item");
      }

app.component.ts

    import { Component } from "@angular/core";
    import {
      animate,
      animateChild,
      group,
      query,
      style,
      transition,
      trigger,
      state
    } from "@angular/animations";
    
    @Component({
      selector: "my-app",
      templateUrl: "./app.component.html",
      styleUrls: ["./app.component.css"],
      animations: [
        trigger("myTrigger", [
          state(
            "fadeInFlash",
            style({
              opacity: "1"
            })
          ),
          transition("void => *", [
            style({ opacity: "0", transform: "translateY(20px)" }),
            animate("500ms")
          ])
        ])
      ]
    })
    export class AppComponent {
      flag: boolean = true;
      items = ["item 1", "item 2", "item 3"];
      state: string = "fadeInFlash";
    
      addItem() {
        if (this.flag) {
          this.flag = !this.flag;
        }
        this.items.push("another item");
      }
    }

app.component.html

    <p>
        Start editing to see some magic happen :)
    </p>
    
    
    
    <p>
        <button (click)="addItem()">Add Item</button>
    </p>
    
    <ul>
        <li *ngFor="let item of items" [@.disabled]="flag" [@myTrigger]='state'> 
        {{item}}</li>
    </ul>
SaiSurya
  • 1,046
  • 8
  • 14
  • 1
    Thanks. There's a console error, though: `ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for '@.disabled': 'true'. Current value: 'false'.` – Steve Nov 02 '20 at 13:51
  • Most Welcome. Please check the updated answer which resolves the console error issue by not using life cycle hook. Coming to the cause of the error you can have reference from https://stackoverflow.com/questions/43375532/expressionchangedafterithasbeencheckederror-explained – SaiSurya Nov 02 '20 at 15:00