AngularJS – Directive compile, pre-link, post-link, controller functions

In this post we will look into the compile and link functions of angular directives. Angular directives are very powerful if used properly. Compile and Link are basic directive functions which need to be understood properly to use angular directives efficiently.

Here is full documentation by angular, on the topics we are going to discuss below https://docs.angularjs.org/api/ng/service/$compile

Order Of Functions

Lets start by defining a simple directive

   
var mod = angular.module('Mod', []);
              
mod.directive('myDir', function () {
                  
return {
                      
restrict: 'E',
                      
controller: function ($scope, $element) {
                          
console.log(': controller');
                          
console.log($element.html());
                      
},
                      
compile: function (tElem, tAttrs) {
                          
console.log(': compile');
                          
console.log(tElem.html());
                          
return {
                              
pre: function (scope, iElem, iAttrs) {
                                  
console.log(': pre link');
                                  
console.log(iElem.html());
                              
},
                              
post: function (scope, iElem, iAttrs) {
                                  
console.log(': post link');
                                  
console.log(iElem.html());
                              
}
                          
}
                      
}
                  
}
              
});
  

Let’s use it in our html code like this

  
<my-dir>
       
Parent
       
<my-dir>Child</my-dir>
  
</my-dir>
  

Above we have defined a very simple directive using all important functions of a directive. We have nested that directly in itself and added parent/child text in the template. Now if we see the output we know the order in which these directives get executed.

  
: compile
  
Parent
  
<my-dir>Child</my-dir>
  
: compile
  
Child
  
: controller
  
Parent
  
<my-dir>Child</my-dir>
  
: pre link
  
Parent
  
<my-dir>Child</my-dir>
  
: controller
  
Child
  
: pre link
  
Child
  
: post link
  
Child
  
: post link
  
Parent
  
<my-dir>Child</my-dir>
  

Looking at the above we can see the order in which these functions execute. This order is always very important, the reason we will see later.

So to conclude the order is:

Compile Parent -> Compile Child -> Controller Parent -> PreLink Parent -> Controller Child -> PreLink Child -> Post Link Child -> Post Link Parent

In above example, we saw that prelink of parent gets execute first but the post link of child gets executed first.

Lets see why this is important with an example

              
var app = angular.module('app', []);
              
app.directive('myDad', function () {
                  
return {
                      
restrict: 'E',
                      
link: function (scope, elem, attr) {
                          
scope.name = 'XXX';
                          
scope.greeting = 'Hello!';
                      
}
                  
};
              
});
              
app.directive('mySon', function () {
                  
return {
                      
restrict: 'E',
                      
link: function (scope, elem, attr) {
                          
scope.sonSays = 'Hey, I am son, and my dad is ' + scope.name;
                      
}
                  
};
              
});
  

[html]

{{greeting}}


{{sonSays}}

[/html]

In the above code we have created two directive “son” and “dad”. The output of above code is

[code]

Hello!

Hey, I am son, and my dad is undefined

[/code]

As you can see, the scope.name comes to be undefined.

The reason for this is, postLink of child is called before parent, hence the scope variable is not present. To fix this, we need to use the preLink function instead.

              
app.directive('myDad', function () {
                  
return {
                      
restrict: 'E',
                      
compile: function (elem, attr) {
                          
return {
                              
pre: function (scope) {
                                  
scope.name = 'XXX';
                                  
scope.greeting = 'Hello!';
                              
}
                          
}
                      
}
                  
};
              
});
  

The above code fixes the problem and we get correct output.

But prelink function is rarely used for this purpose. Lets see what the correct way to share scope through controller.

Sharing Scope Through Controller

In the above example we saw how to pass scope to child directive from parent to child, we did this using preLink function above. There is a better way to do this via controller option which the directive api provide, the preLink function is used very rarely.

              
var app = angular.module('app', []);
              
app.directive('myDad', function () {
                  
return {
                      
restrict: 'E',
                      
controller: function ($scope) {
                          
$scope.name = 'XXX';
                          
$scope.greeting = 'Hello!';
                      
}
                  
};
              
});
              
app.directive('mySon', function () {
                  
return {
                      
restrict: 'E',
                      
require: '^myDad',
                      
link: function (scope, elem, attr) {
                          
scope.sonSays = 'Hey, I am son, and my dad is ' + scope.name;
                      
}
                  
};
              
});
  

In the above, we are using the controller function of a directive and setting scope through this. Also child directive, “require” the parent directive. This way we are establishing a dependency as well and child directive wont work without parent. In the controller we can inject services as usual, do event handing and all other operations.

Directive Compile Function

The directive compile function is the place where you can make any DOM changes which are required, during this phase the directive is still a raw html, no events etc have been attached.

So in summary this is place to make changes in html if any.

You can also add HTML is preLink, postLink function as well but since DOM events, directive are already attached they wont get processed.

In the above code, i have added html in both compile and postLink function. As you can see ng-click works on the compile and not the postLink.

Above we have discussed in detail about the compile, preLink, postLink and controller function of angularjs.

excellence-social-linkdin
excellence-social-facebook
excellence-social-instagram
excellence-social-skype