Sunday 5 June 2016

Order of Execution for Link and Compile Function in Angular Js Directive



       In this post we are going to see the usage of compile function in angular js Directives,  while creating custom directive we many notice that most of the time logic resides in link function, but there is another function which is named as "compile"
In directive we have multiple functions, there is a logic difference between the functions, first is order of execution, second is for what kind of purpose this belongs to.

in General Compile Function executes first, then Pre link function finally post link function will executes, if a series of nested directives there then the order of execution will be

Directive 1: Dir1
Directive 2: Dir2
Directive 3: Dir3

<Dir1>
    <Dir2>
        <Dir3></Dir3>
    </Dir2>
<Dir1>

Compile function (Dir1) --> PreLink function(Dir1)
     Compile function(Dir2) --> PreLink function(Dir2)
       Compile function (Dir3)--> PreLink function(Dir3)
        PostLink function(Dir3)
  PostLink function(Dir2)
PostLink function(Dir1)


HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="application/javascript" src="angular.min.js"></script>
    <script type="application/javascript" src="mod.js"></script>
</head>
<body ng-app="app">
<div ng-controller="mainController">
    <compile-track>
        <degree></degree>
    </compile-track>
</div>
</body>
</html>


so the Compile function and PreLink function are given preference to the Top down approach in nested directives when it is executed, PostLink function are like bottom up approach always last element in the nested directive will execute first and the PostLink function of first element will execute last.


var app = angular.module('app',[]);

app.controller('mainController',['$scope',function($scope){

}]);

Now Let we see some sample, With compile function, Link function:


app.directive('compileTrack',function($compile){
return{
    restrict:'E',
    template:'<div>{{Title}}</div><br/>',
    compile: function (templateelement, attrs) {

        templateelement.append('<span style="font-weight: bold">Author :{{Author}}
        </span><span  style="font-weight: bold">, {{Purpose}}</span>');
return function (scope, instanceelement, attrs) { scope.Author = "Rajesh"; scope.Purpose = 'Architect'; scope.Title = "Angular Sample"; scope.technology = "Core"; var funcTemplate = '<br/><div>Technology : {{technology}}</div>'; instanceelement.append(funcTemplate); console.log('compileTrack : Post Link function'); } } } });


Order of execution of functions:



Output:


Template inside the functions:


From the above code , you can see the template are appended in the two function, one is inside the Compile function, another is inside the link function.But in the output screen, we can see the tempalte append inside the compile function is gives the correct output , but template append inside the link function is not replace with data, why it is so ? because the element passed inside the compile function is just the original template, but the element passed inside the link function is an instance of template,that means it is compiled one, so when ever you add the html or change the template in compile function, it will reflects in UI, but if you change anything inside the compile function then we have to append the template after compiling the code, then only it will bind with data, for example see the below image which will show the element passed as input parameters in both functions.


in compile function it is passed as templateelement, in link function it is passed as instanceelement, that means you can see the difference in template above.

Now we see example of how to change the template inside the link function., here we have to compile and inject.


var compileTemplate = $compile(funcTemplate)(scope);
instanceelement.append(compileTemplate);

app.directive('compileTrack',function($compile){
return{
    restrict:'E',
    template:'<div>{{Title}}</div><br/>',
    compile: function (templateelement, attrs) {

        templateelement.append('<span style="font-weight: bold">Author :{{Author}}</span>' +
            '<span  style="font-weight: bold">, {{Purpose}}</span>');
        console.log('compileTrack : Compile Function');

        return function (scope, instanceelement, attrs) {
            scope.Author = "Rajesh";
            scope.Purpose = 'Architect';
            scope.Title = "Angular Sample";
            scope.technology = "Core";

            var funcTemplate = '<br/><div>Technology : {{technology}}</div>';

         
             var compileTemplate = $compile(funcTemplate)(scope);
             instanceelement.append(compileTemplate);


            console.log('compileTrack : Post Link function');
        }
    }
}
});



Output:
********************


Now we see the example with more elaborate with expansion of Link function to PreLink and Post link, to find the order of execution with some sub directives.

Now we modify the above directive with pre and post link functions to demonstrate more details about the  order of executions:

Now we make the compile function with returning a object of two functions prelink and postlink functions, additionally we will create a another directive which is named as degree to find the order the of execution in nested directives.


app.directive('degree', function () {
    return{
        restrict:'E',
        template:'<div>Education  :{{Name}}</div><br/>',
        compile: function (templateElement,attrs) {
            console.log('Degree : Compile Function');

            return{
                pre: function (scope, instanceElement, attrs) {
                    console.log('Degree : pre Function');
                },
                post: function (scope,instanceElement,attrs) {

                    scope.Name = 'Computer Science Engineering';

                    console.log('Degree : Post Function');
                }
            }
        }
    }
});

app.directive('compileTrack',function($compile){
return{
    restrict:'E',
    transclude:true,
    template:'<div>{{Title}}</div><br/><div ng-transclude></div>',
    compile: function (templateelement, attrs) {

   templateelement.append('<span style="font-weight: bold">Author :{{Author}}</span>' +
            '<span  style="font-weight: bold">, {{Purpose}}</span>');
        console.log('compileTrack : Compile Function');

        return {
            pre: function (scope, instanceelement, attrs) {

                scope.Title = "Angular Sample";
                scope.technology = "Core";
                console.log('compileTrack : pre Link function');
            },
            post:function (scope, instanceelement, attrs) {

            scope.Author = "Rajesh";
            scope.Purpose = 'Architect';

            var funcTemplate = '<br/><div>Technology : {{technology}}</div>';

             var compileTemplate = $compile(funcTemplate)(scope);
             instanceelement.append(compileTemplate);


            console.log('compileTrack : Post Link function');
        }

        }
    }
}
});



Output:



Order of Execution:






From this post you can learn what is the real usage of compile function in angular js. and the order of execution in nested directives




No comments:

Post a Comment