Search code examples
angularjsng-animate

ngAnimate: Tooltip using ngShow is fading out, but not fading in


According to the Angular ngAnimate docs, using class based animation with ngShow is just a matter of using CSS transition with the .foo.ng-hide class. When I do this to show and hide a tooltip, however, the tip appears without the transition. Dismissing the tip, though, shows the fade-out. What am I missing? Codepen here.

When I inspect the code, I see that the ng-animate classes are applied for the fade-out, but not for the fade-in. That is, when angular removes the .ng-hide class, it just removes it without the .ng-hide-animate and ng-hide-remove classes, which I'd expected to see.

HTML

<div ng-app="tooltipping" ng-controller="tipCtrl as tip">
  <ul>
    <li><a href="#" ng-click="tip.toggle()">Toggle the Tip</a> 
      <span class="tip" ng-show="tip.showTip">Tip: Usually 15-20% of the bill.</span>
    </li>
  </ul>
</div>

CSS

li {
  display: block;
  position: relative; 
}
.tip {
  display: block;
  margin-left: 3rem;
  border: 1px solid tomato;
  padding: 1rem;
  position: absolute;
  left: 8rem;
  opacity: 1;
}
.tip.ng-hide {
  transition: 5s ease all;
  opacity: 0;
}

JS

(function(){
  angular.module('tooltipping', ['ngAnimate']);
  angular.module('tooltipping').controller('tipCtrl', function(){
    var vm = this;
    vm.showTip = false;

    vm.toggle = function(){
      vm.showTip = !vm.showTip;
    };
  });
})();

Solution

  • Here's an updated Codepen.

    I've added a second tooltip that works properly, with a class name of .working-tip

    The critical difference is where the transition property is in the CSS. Compare:

    .tip {
      display: block;
      margin-left: 3rem;
      border: 1px solid tomato;
      padding: 1rem;
      position: absolute;
      left: 8rem;
      opacity: 1;
    }
    .tip.ng-hide {
      transition: 3s ease all;
      opacity: 0;
    }
    

    and

    .working-tip {
      display: block;
      margin-left: 3rem;
      border: 1px solid tomato;
      padding: 1rem;
      position: absolute;  
      left: 8rem;
      opacity: 1;
      transition: 3s ease all;
    }
    .working-tip.ng-hide {
      opacity: 0;
    }
    

    The only difference is that the transition property is in the block for the class rather than the class + ng-hide. Doing it the second way results in the expected behavior. I'm still not quite sure why, so I'd love to hear any explanation.