RSS

Optimizing AngularJS Directives By Using Compile Phase

05 Aug

Many AngularJs developers do not use compile phase in directives at all, instead they almost always use link function. I have seen this so much times. But refactoring them later might be painful and might introduce glitches. Learning to use compile function when appropriate is really important skill to have since it will improve performance of your application as well. Consider following AngularJs view fragment,

 <div ng-app="app">
    <div ng-controller="myController">
        <div ng-repeat="fruit in fruits">
            <my-directive fruit="{{fruit}}"></my-directive>
        </div>
    </div>
 </div>

And consider possible naive JS implementation for the directive.

angular.module('app', [])
    .controller('myController', function ($scope) {
    $scope.fruits = ["Bananas", "Apples", "Oranges", "Grapes"];
})
    .directive('myDirective', function ($log) {
    return {
        template: "<div>{{fruit}}</div>",

        link: function (scope, element, attrs) {

                $log.log('link phase:', attrs.fruit);
            
        }
    };
});

As you can see in the above code, common pitfall is all the code that is common to all directive instances and instance specific code in same good old link function! Think how this will impact for the performance of the application, if the directive lives inside of a “ngrepeat” directive and especially if the repeated collection is relatively large performance impact will be augmented. In the above implementation common code is wasting time by executing additional code in each of “ngrepeat” directive’s iterations.

Solution is to use compile function as shown in below implementation.

angular.module('app', [])
    .controller('myController', function ($scope) {
    $scope.fruits = ["Bananas", "Apples", "Oranges", "Grapes"];
})
    .directive('myDirective', function ($log) {
    return {
        template: "<div>{{fruit}}</div>",

        compile: function (element, attrs) {
            // Code in this block will be called once regardless of instance count
            $log.log('compile phase:', attrs.fruit);
            return function link(scope, element, attrs) {
                // Code in this block will be called for each directive instance
                $log.log('link phase:', attrs.fruit);
            };
        }
    };
});

One common use from compile phase is to do template customizations dynamically based on runtime conditions. If you run the above sample code in your browser you would see following console output, notice that compile phase log appears only once but for each iteration in ngrepeat item will be logged through link function of the directive.

directive output

What you should understand is in compile phase scope is not linked to directive content, so there are serious limitations on things you could do within it. What this means is you should avoid using it for registering DOM listeners etc. Compile phase is also useful to do template modifications dynamically hence it will be cloned and propagated to each and every directive instances.

Complete sample is available in following js fiddle.
http://jsfiddle.net/idimuthu/263oo2nw/

Advertisements
 
Leave a comment

Posted by on August 5, 2015 in AngularJs

 

Tags: , , , ,

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

 
%d bloggers like this: