Mysteries around Compile, Link(Pre & Post) for angular directives

Compile: Compile function is to mutate the template before we link to it. It traverses the DOM and collect all of the directives and the result is a linking function. Compile function is executed before the link function. In compile function any manipulation we do for the DOM is only run once, irrespective of how many instances of directives are created. Compiled step is applied to all instances of photo.  Link function deals with specific instance of the directive. Compile returns link function. This return can be object of pre or post link function or just a simple function which by default is post link function. Difference between pre and post function is Pre we have access to element that is linked and not child elements which are not linked. In post we have access to element which is linked and to child elements which are linked as well. You cannot use compile and link function together, you have to use compile function which returns link function.

Link: combine the directives with a scope and produce a live view. Any changes in the scope model are reflected in the view, and any user interactions with the view are reflected in the scope model. Making the scope model a single source of truth. it is used for registering DOM listeners (i.e., $watch expressions on the instance scope) as well as instance DOM manipulation (i.e., manipulation of iElement = individual instance element).It is executed after the template has been cloned. E.g., inside an                              <li ng-repeat…>, the link function is executed after the <li> template (tElement) has been cloned (into an iElement) for that particular <li> element. A $watch() allows a directive to be notified of instance scope property changes (an instance scope is associated with each instance), which allows the directive to render an updated instance value to the DOM — by copying content from the instance scope into the DOM.

Below diagrams summarizes a bit

Compile-pre-post-angular-cycle

Most directives only need a link function, since most directives only deal with a specific DOM element instance (and its instance scope). One way to help determine which to use: consider that the compile function does not receive a scope argument. So the compile function can’t do anything you would want to do that requires an (instance) scope, you can’t $watch any model/instance scope properties, you can’t manipulate the DOM using instance scope information, you can’t call functions defined on the instance scope, etc. However, the compile function (like the link function) does have access to the attributes. So if your DOM manipulations don’t require the instance scope, you can use a compile function. Here’s an example of a directive that only uses a compile function, for those reasons. It examines the attributes, but it doesn’t need an instance scope to do its job. Another way to help determine which to use: if you don’t use the “element” parameter in the link function, then you probably don’t need a link function. If you create a directive that only has a link function, AngularJS treats the function as a post-link function.

In case of nested directives this is how the compile link (Pre and post) functions are executed, lets take an example of following 3 custom directives

In case of nested directives this is how the compile link (Pre and post) functions are executed, lets take an example of following 3 custom directives

Directives-level-1-2-3

3 Functions will be executed in this order

  • Compile – levelOne, levelTwo, levelThree
  • Pre – levelOne, levelTwo, levelThree
  • Post: levelThree, levelTwo,  levelOne

Notice how the order of the compile and pre-link functions calls is identical but the order of the post-link function calls is reversed. After Angular travels down the DOM and has run all the compile functions, it traverses back up again and runs all associated post-link functions. The DOM is now traversed in the opposite direction and thus the post-link functions are called in reverse order. So while the reversed order looked strange a few minutes ago, it is now starting to make perfect sense. This reverse order guarantees that the post-link functions of all child elements have run by the time the post-link function of the parent element is run. So when the post-link function of <level-one> is executed, we are guaranteed that the post-link function of <level-two> and the post-link function of <level-three> have already run. This is the exact reason why it is considered the safest and default place to add your directive logic.

When writing a post-link function, you are guaranteed that the post-link functions of all child elements have already been executed. In most cases that makes perfect sense and therefore it is the most often used place to write directive code. However, Angular provides an additional hook, the pre-link function, where you can run code before any of the child element’s post-link functions have run. The pre-link function is guaranteed to run on an element instance before any post-link function of its child elements has run. So while it made perfect sense for post-link functions to be called in reverse order, it now makes perfect sense to call all pre-link functions in the original order again. This also implies that a pre-link function of an element is run before any of its child elements pre-link functions as well, so for the sake of completeness – A pre-link function of an element is guaranteed to run before any pre-link or post-link function of any of its child elements.

angular-pre-post-compile

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s