Run a directive after the DOM has finished rendering

AD, please don't block.

Let’s suppose you have a custom directive, repeatHelloWorld.

This directive has the important task to log the message “hello world!” in the console, and repeat this operation for the number of times specified by the parameter accepted by the directive, and defined in the controller.

<body ng-controller='stageController'>
  <div repeat-hello-world='{{ repeat }}'></div>
</body>

Controller and directive are defined as:

// Controller
function stageController($scope) {
  $scope.repeat = 5;
}

angular.module('myApp', ['myApp.directives']);

// Directive
angular.module('myApp.directives', [])
  .directive('repeatHelloWorld', function () {
    return {
      link: function (scope, elem, attrs, ctrl) {
        var hello = function () {
          for (var i = 0; i < attrs.repeatHelloWorld; i++) {
            console.log('Hello world!');
          }
        }
        hello();
      }
    }
  });

Everything seem to be ok, but when you run the page, the console remains empty.

This is due to the fact that when the directive is executed the DOM has not already finished the rendering. Indeed it’s enough to add:

console.info(attrs.repeatHelloWorld);
  // > undefined

inside the link function, to prove that attrs.repeatHelloWorld is undefined.

The solution

To run the directive after the DOM has finished rendering you should postpone the execution, for example using the setTimeout function. AngularJS has a method wrapper for the window.setTimeout function, that is $timeout.

$timeout adds a new event to the browser event queue (the rendering engine is already in this queue) so it will complete the execution before the new timeout event.

So in the end in our directive we have just to replace hello with the following:

$timeout(hello, 0);
  // It works even with a delay of 0ms

Take a look at this live demo.