ng-animate with ng-class directive

NicolasMoise picture NicolasMoise · Jan 21, 2014 · Viewed 25.1k times · Source

You can use ng-animate with ng-class with the add and remove animations. I'm looking to make one animation in CSS3 but haven't found good examples with ng-class online. So I was wondering if people have good examples they want to share.

I am not sure what my final animation will look like, but for the purpose of this example let's say I just want to make the height of the div gradually increase when I add the class myclass.

 <div ng-class="{{myclass:scopeVar}}" ng-animate="?????"></div>

**CSS**

.myclass.ng-add{??}
.myclass.ng-add-active{??}
.myclass.ng-remove{??}
.myclass.ng-remove-active{??}

Answer

T J picture T J · Jun 30, 2016

Animating an ng-class addition or removal using CSS transition has 3 stages. The order of these stages are very important, I almost spent a day figuring out why a simple animation wasn't working due incorrect understanding of the order in which classes are added.

Stage 1:

classname-add/classname-remove class is added.

Unlike what someone might think, this is actually added before the class is added to/removed from the element.

This is the stage where we should add the transition property 1 as well as initial state of our animation.

Stage 2:

classname class is added or removed.

This is where you specify the eventual styles of the element. This class often has nothing to do with our animation. Remember that we are animating the addition/removal of this class. This class itself shouldn't even need to be aware that there is an animation taking place around it.

Stage 3:

classname-add-active/classname-remove-active class is added.

This is added after the class is added to/removed from the element.

This is the stage where we should specify the final state of our animation.


To see this in action, let's create a classic fade-in-out animation shown when an element's selected state changes (selected class change using ng-class).

angular.module('demo', ['ngAnimate'])
  .controller('demoCtrl', function($scope) {
    $scope.selected = false;
    $scope.selectToggle = function() {
      $scope.selected = !$scope.selected;
    };
  });
.item {
  width: 50px;
  height: 50px;
  background: grey;
}
.item.selected {
  /* this is the actual change to the elment
   *  which has nothing to do with the animation
   */
  background-color: dodgerblue;
}
.item.selected-add,
.item.selected-remove {
  /* Here we specify the transition property and
   * initial state of the animation, which is hidden 
   * state having 0 opacity
   */
  opacity: 0;
  transition: opacity 3s;
}
.item.selected-add-active,
.item.selected-remove-active {
  /* Here we specify the final state of the animation,
   * which is visible having 1 opacity
   */
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-animate.js"></script>
<div ng-app="demo" ng-controller="demoCtrl">
  <div class="item" ng-class="{selected:selected}"></div>
  <br>
  <br>
  <button ng-click="selectToggle();">
    {{selected? 'Unselect' : 'Select'}}
  </button>
</div>


1 Why should I specify the transition in the first state, instead of just adding it to the class being toggled or a static selector on the element?, you ask.

Well to explain this, assume you need a one-directional animation, for example a fade-out animation when a fade-out class is added.

If you add transition property on the fade-out class itself, the transition stays on the element even after the animation. Which means when your final state (fade-out-add-active) is removed, the element will slowly fade-in back, so we get a fade-out-fade-in which is not what we wanted.