Why Directives?
-
"Web components" (upcoming implementation of w3 spec)
-
Think "reusable" and "encapsulated"
- Angular being awesome
Example
Imagine a loading indicator:

- Used in many places
- Needs to be shown/hidden based on pending API call
- Might have custom code

<img src="/my/asset/loader.gif" id="loader" />
<script>
// ... awesome script to hide/show loader based on promises...
</script>
This would have to be duplicated in every page.
Or in Angular, every controller + view.
Solution: directives
Directives are custom "widgets" of view/logic that are:
Basic Structure of a Directive
myApp.directive('myLoader', function($compile) {
return {
restrict: 'A',
template: '<img src="http://i.stack.imgur.com/MnyxU.gif" />'
}
}
- return an object with certain directive-specific keys
- name "myLoader" will be interpreted in NG as "my-loader"
When to write a directive
DRY
Reuse, ease of use
When it makes your code simpler, not more complex
When not to write a directive
For directives that already exist!
For something that will only be done once
For something trivial
Directives should be the most reduce-able piece of functionality/presentation that you can manage.
If it can easily be done using standard views/controllers and isn't re-used, probably not a good time to write a directive.
"Restrict"
E Element
A Attribute
C Class
M Comment
'Template'
Can use markup or templateUrl to point to remote HTML file
Controller
Create a custom controller with logic, dependency injection, etc. all encapsulated inside the directive itself.
Require
You can "require" the presence of attrs (controllers or directives)
angular.module('docsTabsExample', []).directive('myPane', function() {
return {
require: ['^myTabs', '^ngModel'],
restrict: 'E',
transclude: true,
scope: {
title: '@'
},
link: function(scope, element, attrs, controllers) {
var tabsCtrl = controllers[0],
modelCtrl = controllers[1];
tabsCtrl.addPane(scope);
},
templateUrl: 'my-pane.html'
};
});
"Link" function
Bind to events, observe variable changes
link: function(scope, element, attrs, controller) {
element.on('keydown', function(event) {
alert('key');
})
element.$observe('email', function(old, new) {
})
}
scope is own scope (if isolated) or parent
element is jQuery lite wrapped element
attrs is object map of all element attributes
Isolating scope
creating a scope for your directive
"@"
string will be evaluated before passing
"="
value/object
"&"
method that executes in parent scope
"Transclusion"
Wrapping content with a directive
<my-custom-directive>
<span>Some Awesome text</span>
<div>Some other stuff</div>
</my-custom-directive>
transclude: true
will include child elements in the scope of the directive
transclude: element
will include the entire element and its children