AngularJS Directives Tutorial

Directives are AngularJS way of extending HTML. As the AngularJS Official documentation says, they are basically markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS’s HTML compiler ($compile) to attach a specified behavior to that DOM element (e.g. via event listeners).

In this detailed guide to Directives, I will try to cover every major aspect & options of Directive, including Creating Custom Directives. Since it’s a vast & very important topic, i have created a dedicated post for each one of them, so that we can really go into details if we prefer to. This will also reduce the size of this post, which will otherwise be infinite.

Let’s start. We will cover following topics, in sequence as mentioned below:


Directive’s basics

As mentioned above, Directives are essentially the markers on HTML elements. They extend HTML in following ways:

  • Extending or modifying the behavior of existing elements. Think about ng-show/ng-hide.
  • Creating a brand-new HTML structure which includes rendering & business logic. Think about a custom chart widget.

Directive’s typical usage

Directive are the preferred way to go if we have any of the below mentioned requirements.

  • DOM manipulation
  • Reusing HTML snippets
  • Modifying the behavior of existing elements
  • Integrating with third-party components

Type of Directives

AngularJS directives are created to be used as : attribute, element name, comment or CSS class. Recommended ways are as attribute & element. We will discuss this in deep details in Directive’s restrict option further down in this tutorial.

Built-in Directives

AngularJS provides several built-in directives like ng-app, ng-model, ng-repeat, ng-show, ng-class etc. We have already seen quite a few of them in previous posts. Full list is available at AngularJS Built-in Directives.

Custom Directives

Quite often we will come to the point where built-in directives are simply not enough for our needs. In those cases, we can create custom directives. We will see how to create them in detail in this guide.

Creating a Custom Directive

Directives are created using AngularJS module’s directive function.

angular.module('myApp', [])
.directive('itemWidget', [function() {
   return { //returns Directive Definition Object.
      // Directive definition goes here.
   };
}]);

First argument to the directive function is directive’s name itself. Second parameter is a factory function which is used to setup & configure our directive. This function returns an object known as Directive Definition Object. We will see the content of this object in a moment.

Once declared as above, the directive can then be used in HTML. On every use of our directive in HTML, AngularJS will look into this definition object.

By default, directive can only be used as an attribute of existing element in HTML, for example <div item-widget>. But with the help of some extra configuration (using Directive’s restrict option), we can make it to be used as independent element, like <item-widget>. We will come to that later in this tutorial.

A word on Directive Naming in HTML

AngularJS normalizes the name of a directive in HTML to match in JavaScript. It strips out certain prefix if they are present like [x-, data-] from directive names , and then converts (- , :, _) separated names to camelCase to match the name in javaScript. This means item-widget, Item:widget, data-item_widget or x-item-widget in HTML will all match to itemWidget in javaScript.

Directive Definition Object

Directive definition object contains several key:value pairs. We will discuss each one of them in detail in this guide, starting from template/templateUrl. Based on your particular requirement, you may decide to use several key:value pairs together.

template, templateUrl : Reusing HTML snippets

If the directive has any content that needs to be inserted when the directive is encountered, that can be done using template and templateUrl keys of the directive definition object. If the content is small, template key can be used, whereas if the content is large, templateUrl is preferable which points to the file containing actual content of directive. template & templateUrl are particularly handy for the scenario where you have some HTML that needs to be reused on multiple places in your application. Creating a directive with that content and then just simply using that directive is a nice way of HTML reuse.

Using templateUrl

Live Example:

<html>
	<head>  
		<title>Directive Demo</title>  
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
	</head>
	<body class="jumbotron container" ng-app="myApp">
      
		<div ng-controller="AppController as ctrl">
			<h3>List of Sale Items</h3>
			<div ng-repeat="item in ctrl.items">
				<div item-widget></div>
			</div>
		</div>
      
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js">
      </script>  
      <script>
			angular.module('myApp', [])
			.controller('AppController', [function() {
              var self = this;
			  self.items = [
							{name: 'Computer', price: 500, condition:'New',brand : 'Lenovo', published:'01/11/2015'},
							{name: 'Phone', price: 200, condition:'New',brand : 'Samsung', published:'02/11/2015'},
							{name: 'Printer', price: 300, condition:'New',brand : 'Brother', published:'06/11/2015'},
							{name: 'Dishwasher', price: 250, condition:'Second-Hand',brand : 'WhirlPool', published:'01/12/2015'},
							];
			}])
			.directive('itemWidget', [function() {
				return{
					templateUrl:'saleItem.html'
				}
			}]);
  </script>
  </body>
</html>

In above example, we have declared a simple directive with bare-minimum configuration. We are using only templateUrl key which points to a file [saleItem.html] containing content of directive. Then we have used this directive as an attribute of a div element within ng-repeat loop, passing items from Controller.

Below shown is the directive’s content[saleItem.html].

<div class="panel panel-default">
	<div class="panel-heading">
		Published at:<span ng-bind="item.published | date"></span>
	</div>
	<div class="panel-body">
			Name:<span ng-bind="item.name"></span>
			Condition:<span ng-bind="item.condition"></span>
			Price:<span ng-bind="item.price | currency"></span>
			Brand:<span ng-bind="item.brand"></span>
	</div>
</div>

This is a nice example of HTML reuse. Throw some CSS and you can now make your own amazon/e-bay like item list.

Using template

As mentioned above, if the directive’s content is not large, you may prefer to inline the directive content using template key instead of templateUrl. Let’s rewrite above example using template this time.

Live Example:

<html>
	<head>  
		<title>Directive Demo</title>  
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
	</head>
	<body class="jumbotron container" ng-app="myApp">
      
		<div ng-controller="AppController as ctrl">
			<h3>List of Sale Items</h3>
			<div ng-repeat="item in ctrl.items">
				<div item-widget></div>
			</div>
		</div>
      
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js">
      </script>  
      <script>
			angular.module('myApp', [])
			.controller('AppController', [function() {
              var self = this;
			  self.items = [
							{name: 'Computer', price: 500, condition:'New',brand : 'Lenovo', published:'01/11/2015'},
							{name: 'Phone', price: 200, condition:'New',brand : 'Samsung', published:'02/11/2015'},
							{name: 'Printer', price: 300, condition:'New',brand : 'Brother', published:'06/11/2015'},
							{name: 'Dishwasher', price: 250, condition:'Second-Hand',brand : 'WhirlPool', published:'01/12/2015'},
							];
			}])
			.directive('itemWidget', [function() {
				return{
					template:'<div class="panel panel-default">'+
									'<div class="panel-heading">'+
										'Published at:<span ng-bind="item.published | date"></span>'+
									'</div>'+
									'<div class="panel-body">'+
											'Name:<span ng-bind="item.name"></span>'+
											'Condition:<span ng-bind="item.condition"></span>'+
											'Price:<span ng-bind="item.price | currency"></span>'+
											'Brand:<span ng-bind="item.brand"></span>'+
									'</div>'+
								'</div>'
				}
			}]);
  </script>
  </body>
</html>

As you can see, even if it does the job, in-lining large content with template key can easily become messy. First approach seems better.

That’s it for template/templateUrl configuration. Let’s move to next configuration option [restrict] of Directive Definition Object, which helps us to decide how the directive can be used in HTML.

Next Topic : AngularJS Directive’s restrict option


Please note that if your AngularJS application is using templateUrl to access HTML partials, you will need an HTTP server on front to serve them. This is due to the fact that Browser’s does not allow serving or requesting files on the file:// protocol.

You can use popular Apache HTTP server to serve files. If you need assistance setting-up server,
this post can help you.

Download Source Code

References