1

I have created a directive that fade out and fade in the view on model changes.

app.controller('myCtrl', function($scope, $interval) {
  $scope.number = 0;
  $interval(function() {
    $scope.number++;
  }, 1000);
});

app.directive('fadeOnChange', function($timeout, $animate) {
  return {
    restrict: 'E',

    //We output the value which will be set between fades
    template: '{{theFadedValue.nv}}',

    link: function(scope, elem, attr) {
      //The scope variable we will watch
      var vtw = attr.valueToWatch;

      //We add the anim class to set transitions
      $animate.addClass(elem, 'anim');

      //We watch the value 
      scope.$watch(vtw, function(nv) {

        //we fade out
        var promise = $animate.addClass(elem, 'fade-it-out');

        //when fade out is done, we set the new value
        promise.then(function() {

          scope.$evalAsync(function() {
             scope.theFadedValue = {"nv": nv};
            //we fade it back in
            $animate.removeClass(elem, 'fade-it-out');
          });
        });
      })
    }
  };
});

And here's the view

<div ng-controller="myCtrl">
  <h1><fade-on-change value-to-watch="number"></fade-on-change></h1>
</div>

It works perfectly but I'd like to understand why I need to use $apply, $digest, $timeout or $evalAsync to wrap my call to $animate.removeClass for it to work? If I don't, the class simply does not get removed (which caused me a lot of headaches this afternoon).

I red about those four methods and understand how they are different, but the need to use one of those in this case mystifies me.

plunker

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
Felix D.
  • 2,180
  • 1
  • 23
  • 37

1 Answers1

2

Basically async methods are don't run $digest cycle directly.(exceptional case for $http because it internally wraps inside $scope.$apply())

In your case you are waiting for complete promise which async. That's why you could use $timeout(function(){ }) or $evalAsync, This angular service wrap inside $scope.$apply() & $scope.$apply() internally run the digest cycle and all scope variables gets updated.

$evalAsync run after the DOM has been manipulated by Angular, but before the browser renders

Link here for more information on when to use $scope.$apply()

Hope this will clear your doubts. Thanks.

Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299