Lozah
Lozah

Reputation: 71

How to animate elements on array insertion Angular?

I'm a real newbie in angular animations, never had to use anything else than simple transitions until now. I think what i'm looking for is very simple, yet I can't figure out what I'm missing.

I have an array displayed in template with ngFor. I can insert or delete elements of this array with a simple button click. Right now I have a simple animation taken from the Angular doc to change the opacity of inserted or deleted element :

trigger(
      'inOutAnimation', 
      [
        transition(
          ':enter', 
          [
            style({ opacity: 0 }),
            animate('1s ease-out', style({ opacity: 1 }))
          ]
        ),
        transition(
          ':leave', 
          [
            style({ opacity: 1 }),
            animate('1s ease-in', style({ opacity: 0 }))
          ]
        )
      ]
    )

What I need now is to create an animation to move surrounding elements to their new position on the page. I don't want the existing elements to just pop on their new positions. How can I do this ? Because it looks like the trigger inOutAnimation only targets the added or deleted element. How to manage transitions of other array elements ? Also I was always using moving transitions on elements with known initial and final positions. Now with an array the positions of elements are dynamic.

Your help would be gladly appreciated

EDIT:

https://stackblitz.com/edit/angular-szt5hm

In this example I would like when I click on Add that the div 3 slides/moves to position of 4 instead of just poping. same for 4 to 5 etc.

Upvotes: 4

Views: 4155

Answers (1)

Barremian
Barremian

Reputation: 31105

You could use keyframes to define an animation similar to CSS. Try the following

Controller

import { Component } from '@angular/core';
import { state, keyframes, style, animate, trigger, transition } from '@angular/animations';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  animations: [
    trigger("inOutAnimation", [
      state("in", style({ opacity: 1 })),
      transition(":enter", [
        animate(
          300,
          keyframes([
            style({ opacity: 0, offset: 0 }),
            style({ opacity: 0.25, offset: 0.25 }),
            style({ opacity: 0.5, offset: 0.5 }),
            style({ opacity: 0.75, offset: 0.75 }),
            style({ opacity: 1, offset: 1 }),
          ])
        )
      ]),
      transition(":leave", [
        animate(
          300,
          keyframes([
            style({ opacity: 1, offset: 0 }),
            style({ opacity: 0.75, offset: 0.25 }),
            style({ opacity: 0.5, offset: 0.5 }),
            style({ opacity: 0.25, offset: 0.75 }),
            style({ opacity: 0, offset: 1 }),
          ])
        )
      ])
    ])
  ]
})
export class AppComponent  {
  elements = [
    { value: 1, background: 'green' },
    { value: 2, background: 'red' },
    { value: 3, background: 'blue' },
    { value: 4, background: 'yellow' },
    { value: 5, background: 'pink' }
  ]

  add() {
    this.elements.splice(2, 0, { value: 6, background: 'violet' });
  }

  remove() {
    this.elements.splice(2, 1);
  }
}

Template

<div class="container">
    <div [@inOutAnimation]="'in'" *ngFor="let element of elements" [ngStyle]="{ 'background-color': element.background }">
        {{ element.value }}
    </div>
</div>
<button (click)="add()">Add</button>
<button (click)="remove()">Remove</button>

The animation needs to be bound to the element with the *ngFor to use the :enter and :leave.

I've modified your Stackblitz.

Upvotes: 2

Related Questions