Deep Dive into Angular Directives
Angular directives are very useful in any AngularJS application in order to make code simple and easily handled by a UI Developer. As an angular developer we all use directives frequently but most of us are not aware of the execution cycle of directives that how they work internally. Directives have several inbuilt functions by which we can achieve many functionalities in a simple and concise way.
Thus it is very important to understand their life cycle and how they are created and destroyed. There are four life cycle functions and each has its own importance and order of execution.
Let’s have a look at these execution cycle of functions:
Compile
This function executes only once per and before all other functions. Suppose we have a situation in which we are using our directive inside ng-repeat and we need to execute certain initialization etc. only once then we can write it in compile function.
Controller
Let’s assume we have a situation in which we are using a nested directive, i.e directive inside another directive, and we want to communicate with them. Then a controller can solve that problem.
In simplest word parent, child and sibling directives can communicate to each other by using controller function. Controllers are similar to any other angular controller for our views.
Pre-link
Imagine we have a situation in which we want to use a scope variable of parent directive in child directive. If we define that scoped variable in parent’s link function(which is like a post-link function), and we fetch that variable into child link function then we will not be able to access that variable and it will be undefined, since the execution flow of link function is from child to parent.
But we can solve this issue by defining that scope variable into parent pre-link function and that variable will be fetched properly in child link or pre-link function since pre-link function of parent always executes before link or pre-link function of child.
Post-link
This function is the main work area of directive, and this is where most of us work. It is the same as a link function.
Example:
index.html with three directives(layout as parent, section as child and subsection as grand child)
[js]
<div ng-app="directiveApp">
<div layout-dir>Layout
<div section-dir>Section
<div sub-section-dir>Sub Section
</div>
</div>
</div>
</div>
[/js]
Layout directive which is parent of section and subsection directives:
[js]
var directiveApp = angular.module("directiveApp",[]);
directiveApp.directive(‘layoutDir’, function(){
return {
restrict: ‘EA’,
compile: function compile(){
console.log(‘layout compile function’);
return {
post:function(scope, element, attrs){
console.log(‘layout post link function’);
},
pre: function(scope){
console.log(‘layout pre link function’);
}
}
},
controller: function($scope){
console.log(‘layout controller’);
}
};
});
[/js]
Section directive which is parent of sub section directive and child of layout directive:
[js]
directiveApp.directive(‘sectionDir’, function(){
return {
restrict: ‘EA’,
compile: function(tElement, tAttrs){
console.log(‘section compile function’);
return {
post:function(scope, element, attrs, parentCtrl){
console.log(‘section post link function’);
},
pre: function(scope){
console.log(‘section pre link function’);
}
}
},
controller: function($scope){
console.log(‘section controller’);
}
};
});
[/js]
Sub Section directive which is child of Section directive and grand child of layout directive:
[js]
directiveApp.directive(‘subSectionDir’, function(){
return {
restrict: ‘EA’,
compile: function(){
console.log(‘subSection compile function’);
return {
post:function(scope, element, attrs, parentCtrl){
console.log(‘subSection post link function’);
},
pre: function(scope){
console.log(‘subSection pre link function’);
}
}
},
controller: function($scope){
console.log(‘subSection controller’);
}
};
});
[/js]
If we run the above code we will get the following output:
[js]
layout compile function
section compile function
subSection compile function
layout controller
layout pre link function
section controller
section pre link function
subSection controller
subSection pre link function
subSection post link function
section post link function
layout post link function
[/js]
The execution order of the functions within a directive, and relative to other directives, is as follows:
Parent and child directives also can communicate to each other by requiring parent directive into child directive and calling the functions which are defined in parent controller. See the below code block:
Layout directive
Controller is having addSection and addSubSection functions which will be called by corresponding child directives:
[js]
directiveApp.directive(‘layoutDir’, function(){
return {
restrict: ‘EA’,
compile: function compile(){
console.log(‘layout compile function’);
return {
post:function(scope, element, attrs){
console.log(‘layout post link function’);
element.bind(‘mouseenter’, function(){
console.log(‘mouse enter’, scope.layoutSection);
});
},
pre: function(scope){
console.log(‘layout pre link function’);
}
}
},
controller: function($scope){
$scope.layoutSection = [];
console.log(‘layout controller’);
this.addSection = function(){
$scope.layoutSection.push(‘section’);
};
this.addSubSection = function(){
$scope.layoutSection.push(‘sub section’);
};
}
};
});
[/js]
Section directive
This directive requires parent directive and calls addSection function of layout directive.
[js]
directiveApp.directive(‘sectionDir’, function(){
return {
require: "^layoutDir",
restrict: ‘EA’,
compile: function(tElement, tAttrs){
console.log(‘section compile function’);
return {
post:function(scope, element, attrs, parentCtrl){
console.log(‘section post link function’);
parentCtrl.addSection();
},
pre: function(scope){
console.log(‘section pre link function’);
}
}
},
controller: function($scope){
console.log(‘section controller’);
}
};
});
[/js]
SubSection directive
This directive requires parent directive and calls addSubSection function of layout directive.
[js]
directiveApp.directive(‘subSectionDir’, function(){
return {
require: "^layoutDir",
restrict: ‘EA’,
compile: function(){
console.log(‘subSectio compile function’);
return {
post:function(scope, element, attrs, parentCtrl){
console.log(‘subSectio post link function’);
parentCtrl.addSubSection();
},
pre: function(scope){
console.log(‘subSectio pre link function’);
}
}
},
controller: function($scope){
console.log(‘subSection controller’);
}
};
});
[/js]
So This is basically what there is to know about a directive execution cycle. Hope this will help you in understanding execution cycle of directive and will enhance usability of your directives 🙂
Hi
how can i can call a directive form controller in angular 1.x version