Home » JavaScript » Angular.js » Angular.js Custom Directives Example

About Thodoris Bais

Thodoris is an Oracle Certified Associate Java Programmer and currently works as a Junior Software Developer, for Intrasoft International S.A. He holds a diploma at Informatics & Telecommunications Engineering and is interested in continuous development.

Angular.js Custom Directives Example

1. Introduction

In a previous example we talked about the transclusion concept, in terms of Angular directives.

1.1 What are Directives?

But, what are directives in Angular.js?

1.1.1 A definition

In general, directives is one of the reasons that Angular.js is famous today. They are essentially custom HTML tags and attributes that you can create to do anything one can imagine.

1.1.2 Official Definition

Directives are markers on a DOM element (attributes, CSS classes, names of elements, comments) that tell Angular’s HTML compiler to attach a specific behavior to that DOM element (i.e through event listeners), or even to transform the DOM element and its children. Some of the built-in Angular directives are: ngBind, ngModel and ngClass.

In addition to all the built-in Angular.js directives, you can also create your own directives, by using the .directive function.

Such directives look like this, on their html part:

index.html

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="second.js"></script>
<body ng-app="app">
    <div test-directive></div>
    Hello from page
</body>
</html>

whereas the javascript part is like:

second.js

var app = angular.module("app", []);
app.directive("testDirective", function() {
    return {
        restrict : "EA",
        template : "<h1>Hey, I'm the directive's content!</h1>"
    };
});

As expected, the output firstly contains the template inserted from the directive and then the actual html content of the page itself:

Figure 1. Sample Directive

Figure 1. Sample Directive

Did you notice the transition between the camel-case, used in the js part and the dash (“-“), when on html, according to the directive’s reference?

There are some points here, according to directives:

  • A camel-case name must be used for naming a directive (js), but for invoking it (html), a dash (“-“) separated name must be used (i.e. testDirective -> test-directive).
  • The restrict property is used to restrict the directive’s invocation by some of the existing methods.
  • The template property is used to define the html content that the specified directive will contain.

For instance, the legal restrict values are:

  • E for element’s name
  • A for attribute
  • C for class
  • M for comment

By default, the restrict property has a value of EA, which means that both element names and attribute names can invoke the directive.

In addition, here is the full list of all the possible attributes that one could use into a directive, along with their definitions:

  • restrict : Determines where a directive can be used.
  • scope : Used to create a new child scope or an isolate scope.
  • template : Declares the content that will be displayed from the directive; this, except from pure HTML, can always contain Angular features, too (i.e. data-binding expressions, other directives).
  • templateUrl : Provides the path to the template that should used by the directive. Optionally, this could contain a DOM element id, when templates are defined in <script> tags.
  • controller : The controller module that will be associated with the directive template.
  • link : A function that is mainly used for DOM manipulation tasks
  • priority : specifies the order in which directives are applied to the DOM. (Directives are compiled in priority order, from the highest to lowest. The default priority is “0”.)
  • terminal : if set to true then the current priority will be the last
    set of directives which will execute (any directives at the current priority will still execute as the order of
    execution on same priority is undefined).
  • require : require another directive and inject its controller as the fourth argument to the linking function.
  • type : string representing the document type used by the markup.
  • transclude : compile the content of the element and make it available to the directive.
  • compile : deals with transforming the template DOM. (Since most directives do not do
    template transformation, it is not used often.)

Returning back to our previous small example, what needs to be mentioned is that the directive is restricted to only be invoked either from elements or from attributes ( restrict : "EA" ), but there’s not a specific reason -for this example- to include the E parameter, as its template (HTML part of the directive) here used as an attribute and specifically, a div attribute (<div test-directive></div>). That is, the output would be the same as if we only used the A value ( restrict: 'A' ).

2. How to build Directives

2.1 General Concepts

In general, there are two ways a directive could be built. The one was depicted in the small example above is the Directive Definition Object (DDO), which is like the foundation of a directive. It tells Angular how the directive should be handled during the compilation cycle and what it should do. In technical terms, it is an object returned by the directive declaration that provides instructions to the compiler.

Specifically, the DDO is where you can set things such as how it is going to be marked up in the HTML, how its scope is going to interact with the outside world and if it is going to use the existing HTML or load new HTML into the directive’s content.

The controller function works just like controllers in the rest of your application. It is responsible for initializing the directive’s state and defining the functionality for it as well.

That was a brief introduction to several of the DDO aspects, also declared in the previous’ section relative list of attributes and is proposed for common, daily-usage of directives, which means that for more advanced concepts the above DDO concepts or even the example previously displayed, are not enough. Here come the $compile and $link functions.

2.2 The $compile and $link functions

If you are in the need of a more complex behavior inside your directive (=something that cannot be implemented with an HTML template), the $compile and $link functions come to the rescue. In general, these functions define how the directive is to modify the HTML markup that matched the directive.

The $compile function allows the directive to manipulate the DOM before it is compiled and linked thereby, allowing it to CRUD -if I may say- (ok, just kidding: add/change/remove) directives, as well as, add/change/remove other DOM elements. It is called once for each occurence of the directive in the HTML page. The $compile function finishes its execution, by returning the $link function.

The $link function is called every time the element is about to be bound to data in the $scope object. The concept is that you add the $compile function to the DDO and it has to return the $link function when executed.

In general, here is the standard format of that two:

directive.compile = function(element, attributes) {
    // One-time element configuration.

    var linkFunction = function($scope, element, atttributes) {
        // Bind element to data in $scope.
    }

    return linkFunction;
}

2.3 Link function Example

Before displaying a simple example of the $link function, what should be initially mentioned is the fact that there are many times that the $compile function is not necessary, as you don’t actually need it in your specific directive’s functionality. In that case, only the $link function could be used directly on the DDO.

Let’s now adjust the previous simple example to use the $link function, in order to replace the content of the template attribute, on runtime and specifically, when the template element is about to be bound to data in the $scope object:

index.html

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="app.js"></script>
<body ng-app="myApp">
    <div my-directive ng-controller="myController" >
</div>
</body>
</html>

And here is the angular’s part.

app.js

var myApp = angular.module("myApp", []);
    myApp.directive('myDirective', function() {
        var directive = {};

        directive.restrict = 'A'; 
        template : "

Hey, I'm the directive's content, but I won't be displayed!

" directive.link = function($scope, element, attributes) { element.html("This is the new content, overridden from the $link function: " + $scope.content); element.css("background-color", "#cccccc"); } return directive; }) myApp.controller("myController", function($scope, $http) { $scope.content = "I'm the directive's updated content!"; });

As previously mentioned, I just went only for the attribute (A) restriction here, as line 5 shows. In line 6, we have the common content of the directive’s template, which will not actually be displayed to the end-user, as when the element is about to be bound to data in the $scope object, the $link function will be called and replace the template’s content (line 9), with the content set in the controller (line 18).

As expected and also explained from the above, here is the output:

Figure 2. App screenshot

Figure 2. App screenshot

3. Download the source code

This was an example of Angular.js Custom Directives.

Download
You can download the full source code of this example here: ng-custom-directives.zip

Do you want to know how to develop your skillset to become a Web Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. Building web apps with Node.js

2. HTML5 Programming Cookbook

3. CSS Programming Cookbook

4. AngularJS Programming Cookbook

5. jQuery Programming Cookbook

6. Bootstrap Programming Cookbook

 

and many more ....

 

I have read and agree to the terms & conditions

 

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Kichu
Kichu
6 years ago

Nice example. Thanks you.