Building Angularjs directives
Building Angularjs directives

You will learn how to shape AngularJS directives in order to perform meaningful work in your applications. Directives are perhaps the most flexible and powerful tool available to you in this framework and utilising them effectively is integral to architecting clean and scalable applications. By the same token, it is very easy to fall prey to directive anti-patterns, and in this article, you will learn how to use the features of directives appropriately.

Building a simple element directive

One of the most common use cases of directives is to create custom HTML elements that are able to encapsulate their own template and behaviour. Directive complexity increases very quickly, so ensuring your understanding of its foundation is essential. This recipe will demonstrate some of the most basic features of directives.

How to Do It:-

Creating directives in AngularJS is accomplished with a directive definition object. This object, which is returned from the definition function, contains various properties that serve to shape how a directive will act in your application.

You can build a simple custom element directive easily with the following code:

app.js file

// application module definitionangular.module('myApp', []) .directive('myDirective', function() { // return the directive definition object return { // only match this directive to element tags restrict: 'E', // insert the template matching 'my-template.html' templateUrl: 'my-template.html' }; });
Code language: JavaScript (javascript)

As you might have guessed, it’s bad practice to define your directive template with the template property unless it is very small, so this example will skip right to what you will be using in production: templateUrl and $templateCache. For this recipe, you’ll use a relatively simple template, which can be added to $templateCache using ng-template.
An example application will appear as follows:

index.html file

<!-- specify root element of application --> <div ng-app="myApp"> <!-- register 'my-template.html' with $templateCache --> <script type="text/ng-template" id="my-template.html"> <div ng-repeat="num in [1,2,3,4,5]">{{ num }}</div> </script> <!-- your custom element --> <my-directive></my-directive> </div>
Code language: HTML, XML (xml)

When AngularJS encounters an instance of a custom directive in the index.html template, it will compile the directive into HTML that makes sense to the browser, which will look as follows:

<div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5</div>
Code language: HTML, XML (xml)

How It Work….

The restrict: ‘E’statement indicates that your directive will appear as an element. It simply instructs AngularJS to search for an element in the DOM that has the my-directive tag.

Especially in the context of directives, you should always think of AngularJS as an HTML compiler. AngularJS traverses the DOM tree of the page to look for directives (among many other things) that it needs to perform an action for. Here, AngularJS looks at the element, locates the relevant template in $templateCache, and inserts it into the page for the browser to handle. The provided template will be compiled in the same way, so the use of ng-repeat and other AngularJS directives is fair game, as demonstrated here.

There’s More…

A directive in this fashion, though useful, isn’t really what directives are for. It provides a nice jumping-off point and gives you a feel of how it can be used. However, the purpose that your custom directive is serving can be better implemented with the built-in ng-include directive, which inserts a template into the designated part of HTML. This is not to say that directives shouldn’t ever be used this way, but it’s always good practice to not reinvent the wheel. Directives can do much more than template insertion (which you will soon see), and it’s best to leave the simple tasks to the tools that AngularJS already provides to you.

Working through the directive spectrum

Directives can be incorporated into HTML in several different ways. Depending on how this incorporation is done, the way the directive will interact with the DOM will change.

How To Do It…

All directives are able to define a link function, which defines how that particular directive instance will interact with the part of the DOM it is attached to. The link functions have three parameters by default: the directive scope (which you will learn more about later), the relevant DOM element, and the element’s attributes as key-value pairs.

A directive can exist in a template in four different ways: as an HTML pseudo-element, as an HTML element attribute, as a class, and as a comment.

The element directive:-

The element directive takes the form of an HTML tag. As with any HTML tag, it can wrap content, have attributes, and live inside other HTML elements.

The directive can be used in a template in the following fashion:

index.html file

<div ng-app="myApp"> <element-directive some-attr="myvalue"> <!-- directive's HTML contents --> </element-directive> </div>
Code language: HTML, XML (xml)

This will result in the directive template replacing the wrapped contents of the <element-directive> tag with the template. This element directive can be de ned as follows:

app.js file

angular.module('myApp', []) .directive('elementDirective', function ($log) { return { restrict: 'E', template: '<p>Ze template!</p>', link: function(scope, el, attrs) { $log.log(el.html()); // <p>Ze template!</p> $log.log(attrs.someAttr); // myvalue } }; });
Code language: PHP (php)

Note that for both the tag string and the attribute string, AngularJS will match the CamelCase for elementDirective and someAttr to their hyphenated element-directive and some-attr counterparts in the markup.

If you want to replace the directive tag entirely with the content instead, the directive will be de ned as follows:


angular.module('myApp', []) .directive('elementDirective', function ($log) { return { restrict: 'E', replace: true, template: '<p>Ze template!</p>', link: function(scope, el, attrs) { $log.log(el.html()); // Ze template! $log.log(attrs.someAttr); // myvalue } }; });
Code language: PHP (php)

This approach will operate in an identical fashion, but the directive’s inner HTML will not be wrapped with <element-directive> tags in the compiled HTML. Also, note that the logged template is missing its <p></p> tags that have become the root directive element as they are the top-level tags inside the template.

The attribute directive

Attribute directives are the most commonly used form of directives, and for good reason. They have the following advantages:

  • They can be added to existing HTML as standalone attributes, which is especially convenient if the directive’s purpose doesn’t require you to break up an existing template into fragments.
  • It is possible to add an unlimited amount of attribute directives to an HTML element, which is obviously not possible with an element directive.
  • Attribute directives attached to the same HTML element are able to communicate with each other (refer to the Interaction between nested directives recipe).

This directive can be used in a template in the following fashion:


<div ng-app="myApp"> <div attribute-directive="aval" some-attr="myvalue"> </div> </div>
Code language: HTML, XML (xml)

The attribute directive can be de ned as follows:

app.js file

angular.module('myApp', []) .directive('attributeDirective', function ($log) { return { // restrict defaults to A restrict: 'A', template: '<p>An attribute directive</p>', link: function(scope, el, attrs) { $log.log(el.html()); // <p>An attribute directive</p> $log.log(attrs.attributeDirective); // aval $log.log(attrs.someAttr); // myvalue } }; });
Code language: PHP (php)

Other than its form in the HTML template, the attribute directive functions in pretty much the same way as an element directive. It assumes its attribute values from the container element’s attributes, including the attribute directive and other directives (whether or not they are assigned a value).

The class directive

Class directives are not altogether that different from attribute directives. They provide the ability to have multiple directive assignments, unrestricted local attribute value access, and local directive communication.

This directive can be used in a template in the following fashion:

index.html file

<div ng-app="myApp"> <div class="class-directive: cval; normal-class" some-attr="myvalue"> </div> </div>
Code language: HTML, XML (xml)

This attribute directive can be de ned as follows:

app.js file

angular.module('myApp', []) .directive('classDirective', function ($log) { return { restrict: 'C', template: '<p>A class directive</p>', link: function(scope, el, attrs) { $log.log(el.html()); // <p>A class directive</p> $log.log(el.hasClass('normal-class')); // true $log.log(attrs.classDirective); // cval $log.log(attrs.someAttr); // myvalue } }; });
Code language: PHP (php)

It’s possible to reuse class directives and assign CSS styling to them, as AngularJS leaves them alone when compiling the directive. Additionally, a value can be directly applied to the directive class name attribute by passing it in the CSS string.

The comment directive

Comment directives are the runt of the group. You will very infrequently find their use necessary, but it’s useful to know that they are available in your application.

This directive can be used in a template in the following fashion:

index.html file

<div ng-app="myApp"> <!-- directive: comment-directive val1 val2 val3 --> </div>
Code language: HTML, XML (xml)

The comment directive can be de ned as follows:

app.js file

angular.module('myApp', []) .directive('commentDirective', function ($log) { return { restrict: 'M', // without replace: true, the template cannot // be inserted into the DOM replace: true, template: '<p>A comment directive</p>', link: function(scope, el, attrs) { $log.log(el.html()) // <p>A comment directive</p> $log.log(attrs.commentDirective) // 'val1 val2 val3' } }; });
Code language: PHP (php)

Formerly, the primary use of comment directives was to handle scenarios where the DOM API made it difficult to create directives with multiple siblings. Since the release of AngularJS 1.2 and the inclusion of ng-repeat-start and ng-repeat-end, comment directives are considered an inferior solution to this problem, and therefore, they have largely been relegated to obscurity. Nevertheless, they can still be employed effectively.

How it works…

AngularJS actively compiles the template, searching for matches to de ned directives. It’s possible to chain directive forms together within the same definition. The mydir directive with restrict: ‘EACM’ can appear as follows:

<mydir></mydir> <div mydir></div> <div class="mydir"></dir> <!-- directive: mydir -->
Code language: HTML, XML (xml)

The $log.log() statements in this recipe should have given you some insight into the extraordinary use that directives can have in your application.

Leave a Reply

Your email address will not be published. Required fields are marked *