Ryan Ryan - 21 days ago 7
AngularJS Question

How do I use ng-animate in ng-repeat to shrink items on leave?

I am trying to use the new ng-animate directive, and am struggling to get the desired effect when used with a ng-repeat. I am trying to make items grow when entering, and shrink when leaving. So far the enter is working, but the shrink animation fails.

I have set up a fiddle here so you can see my issue:-

http://jsfiddle.net/rpk98c/6t42M/1/

The relevant HTML is:-

<ul>
<li ng-animate="{enter: 'repeat-enter',
leave: 'repeat-leave',
move: 'repeat-move'}" ng-click="remove($index)" ng-repeat="name in names">{{name}}</li>
</ul>


And the relevant CSS:-

.repeat-enter-setup, .repeat-leave-setup, .repeat-move-setup {
-webkit-transition:all linear 1s;
-moz-transition:all linear 1s;
-ms-transition:all linear 1s;
-o-transition:all linear 1s;
transition:all linear 1s;
}

.repeat-enter-setup {
max-height: 0;
opacity:0;
}
.repeat-enter-setup.repeat-enter-start {
max-height: 250px;
opacity:1;
}
.repeat-leave-setup {
opacity:1;
max-height: 250px;
}
.repeat-leave-setup.repeat-leave-start {
opacity:0;
max-height: 0;
}


Anyone know where I've gone wrong?

Thanks,

Ryan

ps just noticed in IE 10 no animations work! I'm testing in Chrome for now

Answer

You need to switch the first line of the css to affect the "start" classes instead of the setup ones. I know, that's not how they do the examples but it will work. So make it:

.repeat-enter-start, .repeat-leave-start, .repeat-move-start {
  -webkit-transition:all linear 1s;
  -moz-transition:all linear 1s;
  -ms-transition:all linear 1s;
  -o-transition:all linear 1s;
  transition:all linear 1s;
}

This helps because you are trying to animate a property that the element does not usually possess. Elements will not usually have the max-height property set at all. So when you apply a max-height at the same time as the transition it will animate the fact that you added the property! This is before the "start" class is even applied which means that the setup stage will not be finished (since the animation takes 1 second) before the start stage is supposed to begin. So when you apply the "leave" animation the following steps will happen.

  1. You element starts without a max-height.
  2. The "leave-setup" class is applied and gives you max-height and a transition.
  3. Because the max-height just "changed" (from not existing to existing) and you have a transition the browser will now start to animate the max-height from some default starting value (0 it seems) to your chosen value of 250px, so the element immediately shrinks to 0 and starts animating up!
  4. Now the "leave-start" class is applied, but step 3 is not done yet! The max-height is still 0, or close to, since it is still busy animating the inserting of the property, so the animation just stops and goes to 0 again and we never see anything.

But if we move the transition property from the "setup"-step to the "start"-step, like in the css above, step 3 will be instant since it has no transition. The transition appears first at step 4. So we have:

  1. You element starts without a max-height.
  2. The "leave-setup" class is applied and gives you max-height but not transition.
  3. We have no transition so the max height is just instantly changed to 250px.
  4. Now the "leave-start" class is applied, and since step 3 is finished this time around the max-height is now 250px and we can animate away from that without issues.

You don't have this problem with opacity since you are animating from the default value of 1, there is no animation to get in the way in step 3. It also seems that enter events are handled a bit differently since they are more likely to animate from a non-default value, so you will not see this behavior on ever events.

Edit:

I experimented a bit more with this and it turns out my answer does not work for Firefox (at least not on FF Windows). First of all FF seems to just straight up fail if you animate a non existing property, so you need to make sure that your elements have a max-height from the start, something like:

li {
    max-height: 250px;
}

This fixes leave for me, but for some reason no enter animation at all will work in Firefox on windows. Still trying to figure that one out.