AngularJS Directive is what we have close to Web Components at this time and is the most crucial and difficult piece in AngularJS. I’ve not found any suitable article on the web to fully understand directives behavior based on options it takes so I’m writing one. Fingers crossed!
As you may know that directives can be used as an element, an atttribute, a class name, and a comment. Here are the ways we can use our directive angular
in HTML:
<div angular></div> <div class="angular"></div> <angular></angular> <!-- directive: angular -->
For a huge name such as this, you can split the words using hyphens while declaring and camel cased it while defining a directive.
<div the-quick-brown-fox-jumps-over-the-lazy-dog></div>
App.directive('theQuickBrownFoxJumpsOverTheLazyDog', function() {... });
A Quick Demo to load AngularJS logo using the above directive. For your reference, I’m simply injecting an IMG
tag here.
var App = angular.module('App', []); App.directive('angular', function() { return { restrict: 'ECMA', link: function(scope, element, attrs) { var img = document.createElement('img'); img.src = 'http://goo.gl/ceZGf'; // directives as comment if (element[0].nodeType === 8) { element.replaceWith(img); } else { element[0].appendChild(img); } } }; });
How Directive works?
In short, “AngularJS when bootstrapped, looks for all the directives built-in as well as custom ones, compiles them using $compile() method (which keeps track of all the directives associated with an element, sorts them by priority and produces their link function), and links with scope (created by ng-app, ng-controller, ng-include, etc) by registering listeners or setting up $watches resulted in 2 way data bindings between the scope and the element.”
Blueprint?
We’ll take a look at it briefly soon but meanwhile, here is the Directive definition:
var myModule = angular.module(...); myModule.directive('directiveName', function (injectables) { return { restrict: 'A', template: '<div></div>', templateUrl: 'directive.html', replace: false, priority: 0, transclude: false, scope: false, terminal: false, require: false, controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } }, link: function postLink(scope, iElement, iAttrs) { ... } }; });
Now we’ll explore each option aforementioned one by one. You will find working demos along the way as well.
Compile function
For an AngularJS newbie (including myself), its quite confusing to understand compile and link functions in the first place. I initially thought that we can use both the functions in a directive simultaneously which is completely wrong. In fact, a compile function produces a link function. This is the place where you can do the DOM manipulation mostly. This takes 2 arguments by default:
- tElement – A template element the directive has been declared on.
- tAttrs – A list of attributes associated with the tElement.
In addition, you can inject transcludeFn, directiveController, etc. in it. Here is the code snippet for your reference:
<div compile-check></div>
Notice that, tElement
is a jquery object so you do not have to wrap it in $
again.
App.directive('compileCheck', function() { return { restrict: 'A', compile: function(tElement, tAttrs) { tElement.append('Added during compilation phase!'); } }; });
Link function
Its job is to bind a scope with a DOM resulted in a 2-way data binding. You have access to scope here unlike compile function so that you can create custom listeners using $watch method. As expected it takes 3 arguments:
- scope – A scope to be used by the directive.
- element – An element the directive is bound to.
- attrs – A list of attributes associated with the element.
Similar to compile function, you can inject transcludeFn, directiveController, etc. in it.
Why there is a need for a compile function then?
The only reason for the existence of a compile function is performance. Take an example of a directive which consumes a collection and lays out DOM for each item of the collection (similar to ng-repeat). So, if we somehow chain the DOM for each item with a scope then it’ll slow down the whole process because as soon as the scope is created and bound to the DOM – it started watching for change in data. You can imagine how terribly it’ll degrade the performance. This problem is resolved by having 2 way process, a compile method which runs only once for each item and a link method which runs every time the model changes. So, all items will be compiled first and linked later altogether.
Restrict – to be or not to be?
This simply restricts the way you can define a directive. As we’ve seen before, we can restrict it as:
- E: elements
- A: attributes
- C: class names (CSS)
- M: comments
There are different ways to make it HTML5 compliant also. Below is the angular’s built-in directive named, ng-bind
:
<span ng:bind="name"></span> <span ng_bind="name"></span> <span ng-bind="name"></span> <span data-ng-bind="name"></span> <span x-ng-bind="name"></span>
Template
This basically replaces the existing contents of an element. Imagine you want to load your github profile data in a nice card like format in many places on your website but do not want to repeat the same markup all over again. Also, your template can use data bound to $scope
in a controller or $rootScope
unless you have not set scope option (we’ll see it soon) explicitly in the directive definition.
In the below example, I’m simply fetching the angular.js repo information using the github API.
<div ng-controller="DemoCtrl"> <div whoiam>This text will be overwritten</div> </div>
In the directive, you can see that we have not created a new scope for the directive so that the data has been shared between the controller and the directive because its sharing the same scope. You can even override the values for header
as well as footer
within a link function. Go and break things.
var App = angular.module('App', []); // Similar to $(document).ready() in jQuery App.run(function($rootScope) { $rootScope.header = 'I am bound to rootScope'; }); App.controller('DemoCtrl', function($scope) { $scope.footer = 'I am bound to DemoCtrl'; }); App.directive('whoiam', function($http) { return { restrict: 'A', template: '{{header}}<div class="thumbnail" style="width: 80px;"><div><img ng-src="{{data.owner.avatar_url}}"/></div><div class="caption"><p>{{data.name}}</p></div></div>{{footer}}', link: function(scope, element, attrs) { $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) { scope.data = data; }); } }; });
TemplateUrl
If we keep adding more and more details to above card, maintaining the template markups within the directive’s definition will become complicated and unmanageable. So, its better to keep our template in a separate html file and reference its location in templateUrl. As the template loading is asynchronous in this case, so the compilation/linking will be delayed until the template is fully loaded, and will be cached in $templateCache
for later use.
You can either maintain a separate file as mentioned before or wrap it in <script>
tags just like handlebars does. Here is the syntax:
<script type='text/ng-template' id='whoiam.html'></script>
Make sure you set the proper type
otherwise angular will look for the file (specified as id, in this case) on your file system.
In the following example, I’m showing more details on the card. Make a bee line for the demo.
<script type='text/ng-template' id='whoiam.html'> <div class="thumbnail" style="width: 260px;"> <div><img ng-src="{{data.owner.avatar_url}}" style="width:100%;"/></div> <div class="caption"> <p><b>Name: </b>{{data.name}}</p> <p><b>Homepage: </b>{{data.homepage}}</p> <p><b>Watchers: </b>{{data.watchers}}</p> <p><b>Forks: </b>{{data.network_count}}</p> </div> </div> </script>
Replace
In the below screenshot of the example we’d seen before, you can see the elements having angular
directives on them, which are sometimes unnecessary after the directives are compiled by AngularJS.
Thats where replace
option comes handy – If set to true will replace the element having a directive on it with a template. This is what you see after using replace: true
. Check out the demo
You have to use templateUrl/template along with replace.
Priority
As I said earlier, AngularJS finds all directives associated with an element and processes it. This option tells angular to sort directives by priority so a directive having higher priority will be compiled/linked before others. The reason for having this option is that we can perform conditional check on the output of the previous directive compiled. In the below example, I want to add `btn-primary` class only if a div has `btn` class on it.
<div style='padding:100px;'> <div primary btn>The Hitchhiker’s Guide to the Directive Demo</div> </div>
Please note that the default priority if not set will be zero. In this example, btn
directive will be executed before primary
. Play with the demo!
App.directive('btn', function() { return { restrict: 'A', priority: 1, link: function(scope, element, attrs) { element.addClass('btn'); } }; }); App.directive('primary', function() { return { restrict: 'A', priority: 0, link: function(scope, element, attrs) { if (element.hasClass('btn')) { element.addClass('btn-primary'); } } }; });
Terminal
As per the official documentation, If set to true then the current priority will be the last set of directives which will execute on an element. It holds true unless you use custom directives in conjunction with built-in directives having priority set on them such as ngRepeat, ngSwitch, etc. Instead all custom directives having a priority greater than or equal the current priority will not be executed in this case.
In the below example, first
has a higher priority than second
– which has terminal
set to true. And if you set the lower priority to first
– It will not be executed at all. But in case of no-entry
directive, it will not be executed even though it has a higher priority than ng-repeat
. Is it a bug? Is it because of transclusion used in ng-repeat? Need to dig in…
<div first second></div> <ul> <li ng-repeat="item in ['one', 'two', 'three']" no-entry>{{item}} </li> </ul>
App.directive('first', function() { return { restrict: 'A', priority: 3, link: function(scope, element, attrs) { element.addClass('btn btn-success').append('First: Executed, '); } }; }); App.directive('second', function() { return { restrict: 'A', priority: 2, terminal: true, link: function(scope, element, attrs) { element.addClass('btn btn-success').append('Second: Executed '); } }; }); App.directive('noEntry', function() { return { restrict: 'A', priority: 1001, link: function(scope, element, attrs) { element.append('No Entry: Executed '); } }; });
Controller
This can be treated as a control room for a directive. You can either bind properties/methods to $scope
available or this
keyword. The data bound to this
will be accessible in other directives by injecting the controller using require
option. In below example, I’m toggling the state of a lightbulb so that child directives will know about the current state by calling getState()
method – we’ll see it soon.
App.directive('powerSwitch', function() { return { restrict: 'A', controller: function($scope, $element, $attrs) { $scope.state = 'on'; $scope.toggle = function() { $scope.$apply(function() { $scope.state = ($scope.state === 'on' ? 'off' : 'on'); }); }; this.getState = function() { return $scope.state; }; }, }; });
Require
This lets you pass a controller (as defined above) associated with another directive into a compile/linking function. You have to specify the name of the directive to be required – It should be bound to same element or its parent. The name can be prefixed with:
- ? – Will not raise any error if a mentioned directive does not exist.
- ^ – Will look for the directive on parent elements, if not available on the same element.
Use square bracket [‘directive1’, ‘directive2’, ‘directive3’] to require multiple directives
Here is a demo to turn a lightbulb on/off:
<div class="btn btn-success" power-switch> {{'Switched ' + state | uppercase}} <div lightbulb class='bulb' ng-class="bulb"></div> </div>
The below code is self explanatory. She loves me, She loves me not!!
var App = angular.module('App', []); App.directive('powerSwitch', function() { return { restrict: 'A', controller: function($scope, $element, $attrs) { $scope.state = 'on'; $scope.toggle = function() { $scope.$apply(function() { $scope.state = ($scope.state === 'on' ? 'off' : 'on'); }); }; this.getState = function() { return $scope.state; }; }, link: function(scope, element, attrs) { element.bind('click', function() { scope.toggle(); }); scope.$watch('state', function(newVal, oldVal) { if (newVal === 'off') { element.addClass('disabled'); } else { element.removeClass('disabled'); } }); } }; }); App.directive('lightbulb', function() { return { restrict: 'A', require: '^powerSwitch', link: function(scope, element, attrs, controller) { scope.$watch(function() { scope.bulb = controller.getState(); }); } }; });
Scope
This is a scary part but do not worry. Setting scope will only create/maintain the hierarchy between the scope of an element and its parent scope but you can still access data bound to parents’ scopes.
scope: false
Is the default option which does not create a new scope for a directive but shares the scope with its parent. In this basic example to understand scopes, I’ve logged the scope of the directive to the console. You can see that the directive has borrowed the controller’s scope so its parent scope will be $rootScope
in this case.
scope: true
Creates a new scope but prototypically inherits from the parent scope. In below screenshot, the directive has its own scope so that its parent scope will be the controller’s scope, not $rootScope
.
scope: ‘isolate’
Creates an isolated scope which does not prototypically inherit from the parent scope but you can access parent scope using scope.$parent
. Again basic demo!
How can I then share the data between isolated scope and its parent scope as scope.$parent is not much useful in case of templates?
Well, isolated scope takes an object/hash which lets you derive properties from the parent scope and bind them to the local scope. There are three ways to do that:
- @ – binds the value of parent scope property (which always a string) to the local scope. So the value you want to pass in should be wrapped in {{}}. Remember `a` in braces.
- = – binds parent scope property directly which will be evaluated before being passed in.
- & – binds an expression or method which will be executed in the context of the scope it belongs.
In this example, I’m prefixing parent
property with @, children
property with = and shout()
method with &.
<div class='well'> Bound to $rootScope: <input type="text" ng-model="parent"> <div child parent='{{parent}}' shout="shout()"></div> </div> <div class='form well' ng-controller="OneCtrl"> ng-controller="OneCtrl"<br/> <input type="text" ng-model="children"><br/> I am {{children}} and my grandfather is {{parent}} <div child parent="{{parent}}" children="children" shout="shout()"></div> </div>
var App = angular.module('App', []); App.run(function($rootScope) { $rootScope.parent = 'ROOT'; $rootScope.shout = function() { alert("I am bound to $rootScope"); }; }); App.directive('child', function() { return { restrict: 'A', scope: { parent: '@', children: '=', shout: '&' }, template: '<div class="btn btn-link" ng-click="shout()">I am a directive and my father is {{parent || "NIL"}} as well as {{children || "NIL"}}</div>' }; }); App.controller('OneCtrl', function($scope) { $scope.children = 'The One'; $scope.shout = function() { alert('I am inside ng-controller'); }; });
Transclude
There may be a time when you want your directive to consume the existing content of an element into a template. Angular not only lets you transclude the DOM but also gives you a control to insert the transcluded DOM wherever you want using ngTransclude directive. This option tells angular to get ready for transclusion by providing transclude linking function available in a compile function of a directive. There are two ways to use transclude option in directives:
transclude: true
Inside a compile function, you can manipulate the DOM with the help of transclude linking function or you can insert the transcluded DOM into the template using ngTransclude directive on any HTML tag. Notice our old school marquee
tag:
<script type='text/ng-template' id='whoiam.html'> <div class="thumbnail" style="width: 260px;"> <div><img ng-src="{{data.owner.avatar_url}}" style="width:100%;"/></div> <div class="caption"> <p><b>Name: </b>{{data.name}}</p> <p><b>Homepage: </b>{{data.homepage}}</p> <p><b>Watchers: </b>{{data.watchers}}</p> <p><b>Forks: </b>{{data.network_count}}</p> <marquee ng-transclude></marquee> </div> </div> </script>
Please note that ngTransclude will not work in the template if transclude option is not set. Check out Working Demo.
App.directive('whoiam', function($http) { return { restrict: 'A', transclude: true, templateUrl: 'whoiam.html', link: function(scope, element, attrs) { $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) { scope.data = data; }); } }; });
transclude: ‘element’
This transcludes the entire element and a transclude linking function is introduced in the compile function. You can not have access to scope here because the scope is not yet created. Compile function creates a link function for the directive which has access to scope and transcludeFn lets you touch the cloned element (which was transcluded) for DOM manipulation or make use of data bound to scope in it. For your information, this is used in ng-repeat and ng-switch.
<div transclude-element>I got transcluded <child></child></div>
You can inject transcludeFn() in both compile as well as link functions but I’ve not seen the use of it in a link function yet. Demo
App.directive('transcludeElement', function() { return { restrict: 'A', transclude: 'element', compile: function(tElement, tAttrs, transcludeFn) { return function (scope, el, tAttrs) { transcludeFn(scope, function cloneConnectFn(cElement) { tElement.after('<h2>I was added during compilation </h2>').after(cElement); }); }; } }; }); App.directive('child', function(){ return { restrict: 'E', link: function($scope, element, attrs) { element.html(' with my child'); } }; });
Wrap up
I’ve learned a lot of things I was unaware of about AngularJS Directive while writing this post and I hope this will be useful for other lost souls as well. Its funny to say that it seems like AngularJS source code is itself written in Angular.
[…] The Hitchhikers Guide to the Directive […]
[…] (Je vous invite sur ce point à voir la présentation d’Antoine Richard à sujet ou encore ce post), mais non standard pour l’implémenter en […]
Wow, Awesome article. This is the best article I have read about creating directives. It should be in the documentation.
Great article, Angular directive documentation is a bit of a pain. This comes handy!
I wish I found this blog post the moment I started writing directives. I could have saved hours of wandering in circles. Thanks for the great post.
[…] Tutorials The Hitchhiker’s Guide to the Directive […]
a very good stuff, thank you
[…] The Hitchhiker’s Guide to the Directive […]
Even though I posted the pingback to this on my site anti-code.com a while ago, I just finally read this completely lol. Too many projects and too many tabs open haha.
I’m happy I finally did, I get directives better, and $scope. Still stuck on transclude though, wish there was a better explanation of that.and when to use it exactly.
I think the better example is ng-switch wherein the content is shown / completely removed conditionally. And hence transclude=”element” comes handy in this case to have a clone of the element to cache it somewhere before being removed. Later you can compile and inject it again.
[…] The Hitchhiker’s Guide to the Directive […]
[…] The Hitchhiker’s Guide to the Directive […]
[…] The Hitchhiker’s Guide to the Directive […]
[…] The Hitchhiker’s Guide to the Directive […]
Thanks for the great write up. Directives are tricky. On a side note, thanks for your drag-drop directive. I used it to make a logistics board for a client.
Thanks Justin. Glad you use Angular Drag Drop 🙂
Yea. I did run into the issue where I wanted to drag from one pane to another and I could not drag out of the initial pane. The first pane would just get a scroll bar as I tried to drag out of it. I fixed it by using the draggable “helper” option. Maybe this could become an option. You can see my changes here => https://github.com/justinobney/angular-dragdrop/commit/292ab084ef1233aa231eb61ec8bc7b0dc07239a8
This will be a good reference for me now. Though I know how to write directives, not all features and their respective options are properly covered. Now any info is just a Ctrl+F away 🙂
Thanks Aditya.. Glad to hear that.
[…] The Hitchhiker’s Guide to the Directive […]
[…] thought over for some time and recalled that Angular Directive could be a good fit for this kind of problem so I quickly jotted down a very simple piece of […]
Well written article Amit. But can you please explain the part in isolate scope – sharing data within isolate scope and parent scope
What exactly you did not understand in Isolate scope?
I couldn’t understand the difference between ‘=’, ‘@’. playing around with jsfiddle, did help me understand – something like, if I change the directive to,
scope: { scope: {
parent: ‘=’, parent: ‘@’
children: ‘@’, children: ‘=’
}, }
then the HTML would need to be changed as
VS
VS
(aargh, the HTML code got swallowed.) I couldn’t understand the difference between ‘=’, ‘@’. playing around with jsfiddle, did help me understand – something like, created a jsfiddle here.
http://jsfiddle.net/UJTGn/66/
Different between = and @ is very simple. = implies bidirection wherein you can update parent within a directive as it was passed by reference. @ lets you pass the $eval-uated value – passed by value.
Awesome article. Directives take a while to properly understand because they’re complex, flexible and require an understanding of the framework. That said, this article really helped me; definitely the best documentation I’ve read on directives!
[…] the DOM (changing attributes, adding event listeners) directly or through jQuery. You should be using directives instead (p.s. that’s an excellent article, go read […]
Really good article, the best I found on directives. One question though:
What is the prupose of injecting $http and $timeout in the Priority example? (beginner with angular, so sorry)
Glad you liked the article. I think I forgot to remove $http and $timeout – not at all needed in those examples.
Alright, that’s what I thought. Not really misleading, but I was just wondering. Thanks!
Really great guide! Thanks and cheers! 🙂
[…] The Hitchhiker’s Guide to the Directive […]
Excellent information package, thank you. Browsing through many angularJS articles and tutorials, I would suggest you document what version number of angular you have been writing the above for; things seem still quite in flux.
Thanks, you found the information useful. I roger that but as long as you use the stable version, there should not be any problem.
Great article Amit. I look forward to more of these from you.
Thanks Sandeep. Let me know in case you have any topic to write on.
Thank you for this. By far the most detailed explanation on directives I have found. I look forward to other great articles from you.
Really appreciate, Veronica! Let me know if you have topic in mind I can write on?
This needs to be the documentation I couldn’t understand the official stuff at all. Read this once and I’m transcluding away!!! 🙂 TY!
This is amazingly helpful. Thank you so much for the insight
[…] angular, writing a custom directive is the best option to create a component. So lets begin with how we can use a particular component […]
Thank you so much for this compilation!!! Also I think it must be in the official “guide” documentation 😉
This was divine. I took an hour to quietly go though your article and I believe I finally understand directives. Thank you.
Do you happen to know if there’s a way to override a directive’s logic in another directives when you can’t use require (the functions are not exposed in the scope)?
Thanks! If I understood then you probably should use Angular Services to share data between directives and everything else.
@codeformer, thanks for the great write up. It has clarified a lot that I was misunderstanding about Directives. If you don’t mind can you have a look at a dilemma I have regarding Directives and access to child elements: I’ve placed the URL in the website input below.
Kind Regards,
Bazmo
or if not, point me in the right direction for having a directive access it’s child elements to rearrange (not reorder) them?
@codef0rmer I’ve updated the question on stackoverflow with more detail. Sorry to bug you, but this is the only blog I’ve found that comes close to explaining what I want to do.
Check my answer http://stackoverflow.com/a/19874345/415057
Super super awesome article, answered my questions. Thank you so much.
Hello Amit, I am totally new to angular. I am finding it hard to understand the official angularJS documentation. But you have explained in such simple words and good examples. Thanks a lot.
[…] Read More: https://amitgharat.wordpress.com/2013/06/08/the-hitchhikers-guide-to-the-directive/ […]
Very Very Good article.
Great article Amit.
One error, in the description of Link Function the order of the arguments is incorrect. Could be confusing.
Thanks Aaron..! I believe you were talking about the bullets under link method section.
Yep, should have been more specific.
Thanks again for the article, I have come upon it a few times with organic searches. I will definitely send noobz from our local angularjs meetup here.
This should be the official angular directive documentation . Awesome explanation:-)
I’m sure you saved a lot of time for a lot of people. 5 stars
[…] Não são apenas estes atributos que uma diretiva contém, na realidade essa é apenas a ponta do iceberg, caso você queira ver quais atributos você pode usufruir para montar uma diretiva, eu aconselho você a ler este guia. […]
[…] Não são apenas estes atributos que uma diretiva contém, na realidade essa é apenas a ponta do iceberg, caso você queira ver quais atributos você pode usufruir para montar uma diretiva, eu aconselho você a ler este guia. […]
In the terminal example, if you set the no-entry priority to 100, then it functions correctly. I think 1001 is too high
Here is a modified fiddle demo. It looks like 999 is the largest valid priority number.
Hey csrow, ngRepeat has a priority set to 1000 (with terminal: true) that means all directives having priority higher than 1000 should only be executed. It seems to be working for custom directives but not in conjunction with built-in directives – where its actually reverse.
Why does having more than one element in the template when replace:true stops the operation? For instance, with template: ‘123abc’ will not work with replace:true.
Let’s try again. HTML is not posting correctly.
[…] The Hitchhiker’s Guide to the Directive | codef0rmer https://amitgharat.wordpress.com/2013/06/08/the-hitchhikers-guide-to-the-directive/ […]
[…] The Hitchhiker’s Guide to the Directive […]
Thank you for writing this up!
There’s one thing that popped out to me that could be misleading: “This problem is resolved by having 2 way process, a compile method which runs only once for each item and a link method which runs every time the model changes.”
I know you’re in the context of talking about ng-repeat but saying that the link method runs every time the model changes could be confusing. As I understand it the link method is run when items are added to the model (and which will be added to the view), but link would not run when items are removed though the model has changed. I think the point is that the compile step produces a “template” (unfortunately that word is overloaded in this context) from which an instance is created by ng-repeat for each item in the model. When the instances are created from the template, the link function is called to associate the new item with its proper $scope.
Also, I’m also not sure what you mean by “chain the DOM” a bit before this though as I understand it you are definitely right that the compile step is there so Angular doesn’t have to go through parsing the HTML every time it needs to create a new instance within ng-repeat as that would be a huge performance problem.
Hey dadeng,
Yes, I was talking in the context of ngRepeat there. I meant by “chain the DOM” is about making a link between the DOM and it’s scope.
Thank you for the clarification!
This was extremely helpful. Thanks for the post!
[…] The Hitchhiker’s Guide to the Directive […]
it seems that the use of transcludeFn function is now moved in link and not in compile
Hey Nicolas, I did not understand your point. Can you please elaborate?
Hello. Nice explanation. But an important comment to reflect changes between the version of angular you used in your ‘priority’ example and modern versions. Angular performs link and compile in priority order as stated in older versions. But in 1.2.16, the latest stable version, angular goes in reverse order when linking.
From the docs “When there are multiple directives defined on a single DOM element, sometimes it is necessary to specify the order in which the directives are applied. The priority is used to sort the directives before their compile functions get called. Priority is defined as a number. Directives with greater numerical priority are compiled first. Pre-link functions are also run in priority order, but post-link functions are run in reverse order. The order of directives with the same priority is undefined. The default priority is 0.”
Thus I had to make directive ‘primary’ have a higher priority than directive ‘btn’. Hope this helps all those having fun learning Angular!!!
Thanks Edwin, Yeah I noticed that but did not get time to upgrade the draft. Thanks for pointing out, I’ll copy paste your comment as is 🙂
Some truly select blog posts on this web site , saved to fav. eecekaedakge
[…] The Hitchhiker’s Guide to the Directive […]
[…] The Hitchhiker’s Guide to the Directive […]
[…] the DOM (changing attributes, adding event listeners) directly or through jQuery. You should be using directives instead (p.s. that’s an excellent article, go read […]
[…] Directives […]
[…] The Hitchhiker’s Guide to the Directive […]
[…] The Hitchhiker’s Guide to the Directive […]
[…] Directives – The hitchhiker’s guide to the directive […]
[…] Directives – The hitchhiker’s guide to the directive […]
[…] Directives – The hitchhiker’s guide to the directive […]
Very good article!!
Its just awesome. Its called learning with fun.
[…] approached me to write a book especially on AngularJS Directives after getting impressed by The Hitchhiker’s Guide to the Directive blog post. I’m glad that lots of people found the blog post very useful but there were many […]
really good write-up. complete, concise, and understandable. thank you so much for taking the time to do this, it will save me many hours of beating my head against the wall.
[…] The Hitchhiker’s Guide to the Directive […]
[…] Статья: автостопом по AngularJS Directive; […]
[…] The Hitchhiker’s Guide to the Directive | codef0rmer – […]
[…] If you want to dive in further under the hood of directives, here is what I like to call the Unofficial AngularJS Directive Reference […]
[…] Directives – The hitchhiker’s guide to the directive […]
[…] Статья: автостопом по AngularJS Directive; […]
I’m new to angular and looking forward to learning to write directives this article might help to understand directives in better. Thanks for the article