Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fire an event immediately after $scope.$digest

In my AngularJS app, there's several points at which I want to wait for a $scope to be processed into the DOM, and then run some code on it, like a jQuery fadeIn, for example.

Is there a way to listen for a "digestComplete" message of some sort?

My current method is: immediately after setting whatever $scope variables I want rendered, use setTimeout with a delay of 0 ms, so that it will let the scope finish digesting, and then run the code, which works perfectly. Only problem is, I very occasionally see the DOM render before that setTimeout returns. I'd like a method that is guaranteed to fire after digest, and before render.

like image 236
doubledriscoll Avatar asked Aug 24 '12 02:08

doubledriscoll


People also ask

What does scope digest do?

$digest() The $scope. $digest() function iterates through all the watches in the $scope object, and its child $scope objects (if it has any). When $digest() iterates over the watches, it checks if the value of the expression has changed.

How do you fix $Digest already in progress?

There are a few ways to deal with this. The easiest way to deal with this is to use the built in $timeout, and a second way is if you are using underscore or lodash (and you should be), call the following: $timeout(function(){ //any code in here will automatically have an apply run afterwards });

Which function is used to trigger the digest cycle process manually?

In this case it's your responsibility to call $apply() manually, which triggers a $digest cycle.

What is Angular digest cycle?

Digest cycle is what Angular JS triggers when a value in the model or view is changed. The cycle sets off the watchers which then match the value of model and view to the newest value. Digest cycle automatically runs when the code encounters a directive.


1 Answers

In this jQuery fade-in-and-out fiddle (which I found it on the JSFiddles Examples wiki page), the author defines a "fadey" directive and performs the jQuery fadeIn (or fadeOut) in the directive's link function"

<li ng-repeat="item in items" fadey="500">
...
myApp.directive('fadey', function() {
return {
    restrict: 'A',
    link: function(scope, elm, attrs) {
        var duration = parseInt(attrs.fadey);
        if (isNaN(duration)) {
            duration = 500;
        }
        elm = jQuery(elm); // this line is not needed if jQuery is loaded before Angular
        elm.hide();
        elm.fadeIn(duration)

Another possible solution is to use $evalAsync: see this comment by Miško, in which he states:

The asyncEval is after the DOM construction but before the browser renders. I believe that is the time you want to attach the jquery plugins. otherwise you will have flicker. if you really want to do after the browser render you can do $defer(fn, 0);

($defer was renamed $timeout).

However, I think using a directive (since you are manipulating the DOM) is the better approach.

Here's a SO post where the OP tried listening for $viewContentLoaded events on the scope (which is yet another alternative), in order to apply some jQuery functions. The suggestion/answer was again to use a directive.

like image 58
Mark Rajcok Avatar answered Sep 28 '22 08:09

Mark Rajcok