I have developed a custom directive that smoothly fades out and fades in the content whenever there is a change in the model.
app.controller('myCtrl', function($scope, $interval) {
$scope.number = 0;
$interval(function() {
$scope.number++;
}, 1000);
});
app.directive('fadeOnChange', function($timeout, $animate) {
return {
restrict: 'E',
//Displaying the value with transition effects
template: '{{theFadedValue.nv}}',
link: function(scope, elem, attr) {
//Watching the specified variable on scope
var vtw = attr.valueToWatch;
//Adding animation class for transitions
$animate.addClass(elem, 'anim');
//Watching the value changes
scope.$watch(vtw, function(nv) {
//Fade out effect
var promise = $animate.addClass(elem, 'fade-it-out');
//After fade out, updating the new value
promise.then(function() {
scope.$evalAsync(function() {
scope.theFadedValue = {"nv": nv};
//Fading it back in
$animate.removeClass(elem, 'fade-it-out');
});
});
})
}
};
});
Here is how the view looks like:
<div ng-controller="myCtrl">
<h1><fade-on-change value-to-watch="number"></fade-on-change></h1>
</div>
The functionality works flawlessly, but I am curious as to why I need to use $apply, $digest, $timeout or $evalAsync to encapsulate my call to $animate.removeClass in order for it to work properly. Without them, the class does not get removed as expected, leading to some confusion.
I have read about these methods and their distinctions, yet the necessity of using one of them specifically in this scenario perplexes me.