WiRo WiRo - 3 months ago 25
AngularJS Question

ngAnimate - Animation not triggered on repeated custom directive

I want to use ngAnimate on a custom directive which is repeated using ng-repeat.
The animations work just fine if I use ng-repeat on a simple html list-item. However, as soon as replace the list-item by a custom directive element the animation is not triggered.

What am I missing/doing wrong?

Code ( Plunker Demo ):

HTML

<h3>Simple ng-repeat</h3>
<ul>
<li class="animate-repeat" ng-repeat="val in testValues">{{ val }}</li>
</ul>

<h3>ng-repeat on custom directive</h3>
<ul >
<animation-test class="animate-repeat" ng-repeat="val in testValues" test-val="val"></animation-test>
</ul>


Javascript

var app = angular.module('application', ['ngAnimate']);

app.controller('mainController', [ '$scope', mainController]);

function mainController($scope){

// just for demo purposes
$scope.testValues = [];

$scope.addItem = function(){
var len = $scope.testValues.length;
$scope.testValues.unshift('Value #' + len);
};

$scope.removeItem = function(){
$scope.testValues.pop();
};

}

app.directive('animationTest', animationTest);

function animationTest(){

return {
template: ' <li> {{testVal}} </li> ',
scope: {
testVal: '<'
}
};
}


CSS (uses animate.css )

.animate-repeat.ng-enter {
animation: 0.5s slideInUp;
}

.animate-repeat.ng-leave,
.animate-repeat.ng-move {
animation: 0.5s slideOutDown;

}



@-webkit-keyframes slideInUp {
from {
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
visibility: visible;
}

to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}

@keyframes slideInUp {
from {
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
visibility: visible;
}

to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}

.slideInUp {
-webkit-animation-name: slideInUp;
animation-name: slideInUp;
}

@-webkit-keyframes slideOutDown {
from {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}

to {
visibility: hidden;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
}

@keyframes slideOutDown {
from {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}

to {
visibility: hidden;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
}

.slideOutDown {
-webkit-animation-name: slideOutDown;
animation-name: slideOutDown;
}

Answer

You can simply bind the directive to a <li> element which will then make your exact code work. So just change the HTML for the directive to this:

<li animation-test class="animate-repeat" ng-repeat="val in testValues" test-val="val"></li>

And your directive would be:

app.directive('animationTest', animationTest);

  function animationTest(){

  return {
    template: '{{testVal}}',
    scope: {
      testVal: '<'
    }
  };
}

CodePen demo

Or if you want to make it your way you need to just add a class for the directive element ie. directive-block and then set the animations to the directive element itself like this:

HTML:

<animation-test class="directive-block" ng-repeat="val in testValues" test-val="val"></animation-test>

CSS:

.directive-block {
  display: block;
  animation: 0.5s slideInUp;
}

.directive-block.ng-leave-active {
  animation: 0.5s slideOutDown;
}

CodePen demo