23

I have a component that fetches list of items from server and then display that list using *ngFor in template.

I want the list to be displayed with some animation, but one after other. I mean each list item should animate in after other.

I am trying something like this:

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

@Component({
    selector: 'list-item',
    template: ` <li  @flyInOut="'in'">{{item}}</li>`,
    animations: [
        trigger('flyInOut', [
            state('in', style({ transform: 'translateX(0)' })),
            transition('void => *', [
                style({ transform: 'translateX(-100%)' }),
                animate(100)
            ]),
            transition('* => void', [
                animate(100, style({ transform: 'translateX(100%)' }))
            ])
        ])
    ]
})
export class ListItemComponent {
    @Input() item: any;
}

and in my list component template I am using it like:

<ul>
    <li *ngFor="let item of list;">
     <list-item [item]="item"></list-item>
    </li>
</ul>

What it does is displays whole list at once. I want items to enter one by one with some animation.

Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
Naveed Ahmed
  • 10,048
  • 12
  • 46
  • 85
  • 1
    Exact same behavior expected for me ! Have you find a solution ? – Christophe Gigax Oct 03 '16 at 12:37
  • Not yet, but it seems that with the new animation module in Angular 2, it shouldn't be much difficult now. We can create a component for list item and then attached the animation for on enter and leave. Check https://angular.io/docs/ts/latest/guide/animations.html – Naveed Ahmed Oct 08 '16 at 16:15
  • I've seen, thanks ! My solution was to set a timeout between each element for the animation, so all LI element enters smoothly with an animation – Christophe Gigax Oct 11 '16 at 11:11
  • Have a look at http://stackoverflow.com/questions/37880525/angular-2-staggering-animation. Staggering is not implemented yet. – sebap Nov 16 '16 at 09:43

3 Answers3

17

I couldn't find stagger support on ngFor in the documentation, but there's now animation.done events, which can be used to make staggering ngFor

StackBlitz

@Component({
  selector: 'my-app',
  template: `
    <ul>
    <li *ngFor="let hero of staggeringHeroes; let i = index"
        (@flyInOut.done)="doNext()"
        [@flyInOut]="'in'" (click)="removeMe(i)">
      {{hero}}
    </li>
  </ul>
  `,
  animations: [
  trigger('flyInOut', [
    state('in', style({transform: 'translateX(0)'})),
    transition('void => *', [
      animate(300, keyframes([
        style({opacity: 0, transform: 'translateX(-100%)', offset: 0}),
        style({opacity: 1, transform: 'translateX(15px)',  offset: 0.3}),
        style({opacity: 1, transform: 'translateX(0)',     offset: 1.0})
      ]))
    ]),
    transition('* => void', [
      animate(300, keyframes([
        style({opacity: 1, transform: 'translateX(0)',     offset: 0}),
        style({opacity: 1, transform: 'translateX(-15px)', offset: 0.7}),
        style({opacity: 0, transform: 'translateX(100%)',  offset: 1.0})
      ]))
    ])
  ])
]
})
export class App {
  heroes: any[] = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India'];

  next: number = 0;
  staggeringHeroes: any[] = [];

  constructor(){
    this.doNext();
  }

  doNext() {
    if(this.next < this.heroes.length) {
      this.staggeringHeroes.push(this.heroes[this.next++]);
    }
  }

  removeMe(i) {
    this.staggeringHeroes.splice(i, 1);
  }
}
Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
  • In your case you have a static area, but what we can do when the array changes ? – Kévin Vilela Pinto Feb 03 '17 at 17:59
  • Is it possible to achieve the same transition effect with custom transition `stateChangeExpression` - other than `void => *` (`:entry`) / `* => void` (`:leave`) **for `*ngFor`**? For example define `transition('in',...` and `transition('out',...` and in template use `[@flyInOut]="transition"` with binding to `transition` variable in the component class?. I ask because `*ngFor` makes DOM addition and removal and I not successful to achive that with custom transitions. – Felix Apr 09 '18 at 13:32
  • It would be nice if you can update the plunker with something else, I think stackblitz is a good one! – Mohammad Kermani May 15 '18 at 13:19
1

To use the angular2 animations I set a state property to the iterated item and then just setup a toggle function for the mouseover and mouseout functions. This way each item encapsulated it's animated state and then I could change it as needed

<li
   *ngFor="let item of itemsList"
   (mouseover)="toogleAnimation(item)"
   (mouseout)="toogleAnimation(item)"
>{{ item.name }}
  <div class="animation_wrapper" [@slideInOut]="item.state">
    <span class="glyphicon glyphicon-refresh"></span>
    <span class="glyphicon glyphicon-trash"></span>
  </div>
</li>
jredd
  • 198
  • 2
  • 12
  • Is `slideInOut` supposed to be `flyInOut` in your example? – ryanm Dec 29 '17 at 16:12
  • If you are referring to the flyInOut in the earlier posts, I guess you could say it's supposed to be that, but thats a literal example from my code. Remember you can name trigger names anything you want as long as you call on them properly – jredd Dec 30 '17 at 18:50
  • 1
    Yes, indeed to naming triggers (almost) anything. Just wanted to see how your answer matched up to the OP's question. Thanks and happy new year! – ryanm Jan 04 '18 at 22:26
0

what you want, of the time between each item in the list, see this code. change the file .css to .scss

like this https://codepen.io/jhenriquez856/pen/baPagq

$total-items: 5;

body {
  font-family: sans-serif;
  background: #111;
  color: #fff;
}

ul {
  width: 300px;
  left: 50%;
  margin-top: 25px;
  margin-left: -150px;
  
  position: absolute;
}

li {
  position: relative;
  display: block;
  border: 1px solid hotpink;
  margin-bottom: 5px;
  padding: 10px;
  text-align: center;
  text-transform: uppercase;
  animation: fadeIn 0.5s linear;
  animation-fill-mode: both;
}

// Set delay per List Item
@for $i from 1 through $total-items {
  li:nth-child(#{$i}) {
    animation-delay: .25s * $i;
  }
}

// Keyframe animation
@-webkit-keyframes fadeIn {
  0% {
    opacity: 0;
  }
  75% {
    opacity: 0.5;
  }
  100% {
    opacity: 1;
  }
}
<ul>
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
</ul>