I can't figure out why the following animation doesn't work as it should:
app.directive('openMenu', ['$animate', '$timeout', function($animate, $timeout) {
return {
link: function(scope, elem) {
elem.bind('click', function() {
if(elem.is(':animated'))
return;
$timeout(function() {
$animate.addClass(elem, 'see');
}, 0);
});
}
}
}]);
And in this one the animation doesn't work at all (and class is not added either):
app.directive('openMenu', ['$animate', function($animate) {
return {
link: function(scope, elem) {
elem.bind('click', function() {
if(elem.is(':animated'))
return;
$animate.addClass(elem, 'see');
});
}
}
}]);
In the second code snippet I only removed $timeout
, which is 0, I tried to use self-firing functions to check - animating works only when I am using timeouts. Can someone explain me why?
middle {
margin-left: 0;
}
middle.see {
margin-left: 270px;
}
.middle.see-add {
-webkit-transition: margin-left 300ms;
-moz-transition: margin-left 300ms;
-ms-transition: margin-left 300ms;
-o-transition: margin-left 300ms;
transition: margin-left 300ms;
margin-left: 0;
}
.middle.see-add.see-add-active {
margin-left: 270px;
}
Here is the markup:
<div class="middle" open-menu></div>
Your problem is that you happen to be out of the Angular life-cycle. You are using
.bind
so Angular will not be notified whenever something has changed. The$timeout
works because it's a one of the wrappers to notify Angular about an outside change. You could also use$apply
. Both, the$timeout
and$apply
take a callback which will be executed. After the callback is finished Angular starts adigest
beginning at therootScope
. Now every binding will be updated and everything should work properly.Since your directive uses jQuery and jQuery modify the DOM, we need to tell angular about it. To do so, you need to do $scope.$apply but you would run into the error : "digest already in progress".
The code executed inside the $timeout guarantee that your code will be safely executed on the next digest cycle.
0 is the default value, you don't even need to specify it. You could simply write :
The $timeout service is simply a convenient service equivalent to :
You can find extensive information about the digest mechanism in the official documentation : https://docs.angularjs.org/error/$rootScope/inprog
I think it's because
elem.bind('click')
is a jQuery function, which is running outside of the angular digest phase.Probably this would work as well instead of using
$timeout
: