Making my own angular.js directives with the module api

Directives are a big part of angular.js web application development. If you have ever used angular at all you have used at least some built in directives such as ng-app, and ng-repeat. However it is possible to create your own directives using the directive method in the module api when creating an angular module.

Whats really cool about this is that It allows for me to create my own html elements, and attributes. In other words it allows for me to extend the functionally of html, and make something very complicated as simple as just having an element in an html document like this.

1
<x-my-element></x-my-element>

Basic example of making a directive in angularjs

It is possible to make directives in a way where they can be elements, attributes, classes, and event comments. For my basic demo of this lets start with an attribute.

1
2
3
4
5
<div ng-app="app">
<div first-directive></div>
</div>

So then my angular module that I will be calling simply app will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
var app = angular.module('app', []);
app.directive('firstDirective', function () {
return {
restrict: 'AE',
replace: 'true',
template: '<p>My own directive</p>'
};
});

This will inject the text my own directive into any element in which I use it. Of course it can be something much more than just a simple string, but hopefully you get the basic idea.

The object to return when using module.directive

When using the directive method I will want to return an object with at least a template, replace, and restrict properties. The template is of course the html that will be used in my directive, replace set to true means that any content in the element used with the directive will be replaces with what I am defining in my directive. The restrict property is used to tell angular that this directive can be used as an element, or an attribute.

Heres a full list of the properties of this object that is returned in module.directive:

  • restrict - What the directive should be restricted to in html, In this demo it can be used as an Element or an attribute. If I want to use the directive as an element, attribute, and class I would want to set it to “AEC”

  • replace - If set to true the directive will replace what may be inside the element with what is generated, else if false the content will be appended to whatever may be there to begin with.

  • template - This is of course the html that is to be used. It does not have to be a simple string, it can involve other directives, and so forth.

  • templateUrl - this can be used to link to an external template

  • link - add custom $scope to a directive.

  • compile - I use this if I need to do something once during the angular compile phase.

directives and $scope of a controller

The new directive that I make does not get it’s own scope, at least not out of the gate, instead it uses the scope of its parent element.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.directive('useController', function () {
return {
restrict: 'AE',
replace: 'true',
template: '<p>{{mess}}</p>'
};
});
app.controller('the-controller', function ($scope) {
$scope.mess = 'using the controller';
});

It is possible to append some things to $scope if they are not given from the parent element, This is where the link property comes into play.

If I want to add some custom stuff to $scope i can do so with the link property of the object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
app.directive('addScope', function () {
return {
restrict: 'AE',
replace: 'true',
template: '<p>{{mess}}</p>',
link: function (scope, el, att) {
if (!scope.mess) {
scope.mess = 'this is some local stuff.';
}
}
};
});

the compile property

The compile property is useful i find myself in a situation in which I want to do something during the compile phase of angulars life cycle. For the most part link alone will work fine with what I want to accomplish, but in some cases it might be a bit more efficient.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
app.directive('many', function () {
return {
restrict: 'AE',
replace: 'true',
template: '<div><p>{{p.mess}}</p></div>',
compile: function (el, att) {
console.log('complie');
return this.link;
},
link: function (scope, el, att) {
console.log('link');
if (!scope.p) {
scope.p = {mess:'single use'};
}
}
};
});
app.controller('manyControl', function ($scope) {
$scope.obj = [{
mess: 'one'
}, {
mess: 'two'
}, {
mess: 'three'
}
];
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div ng-app="app">
<div ng-controller="manyControl">
<!-- repeat -->
<div ng-repeat="p in obj">
<data-many></data-many>
</div>
<!-- single use -->
<data-many></data-many>
</div>
</div>

conclusion

This might be one of the most useful aspects of angular. It allows to take something that might be a bit of a mess and structure it in a way in which it is all pretty easy to follow. I am still a little new to angular, but so far I can clearly see why this framework is so popular.