Angularjs – Directives in detail

Let me first thank to Mr.Sandeep Panda for detail explanation in sitepoint. Now i gonna repeat the same with summarizing in a simple manner.

Overview

A directive is something that introduces new syntax. Directives are markers on a DOM element which attach a special behavior to it. For example, static HTML does not know how to create and display a date picker widget. To teach HTML this new syntax we need a directive. The directive will somehow create an element that behaves like a date picker. We will see how this is achieved subsequently.

If you’ve written an Angular application before, then you have used directives, whether you realized it or not. You might have used simple directives like ng-model,ng-repeat,ng-show, etc. All these directives attach special behavior to DOM elements. For example, ng-repeat repeats a specific element and ng-showconditionally shows an element. If you want to make an element draggable/droppable you might create a directive for that too. The basic idea behind directive is very simple. It makes your HTML truly interactive by attaching event listeners to the elements and/or transforming the DOM.

The jQuery Perspective

Just imagine how you create a date picker with jQuery. We first add a normal input field to the HTML and then in jQuery we call $(element).datePicker() to actually convert it to a date picker. But, think about it. When a designer comes and examines the markup, can he/she immediately guess what the field actually is? Is it just a plain input field or a date picker? You have to look into the jQuery code to be sure. The Angular approach is to use a directive to extend HTML. So, a directive for a date picker can look like this:

1
<date-picker></date-picker>

Or it could look like this:

1
<input type="text" date-picker/>

Building Custom Directives:

An Angular directive comes in four flavors in terms of appearance.

  1. A new HTML element (<date-picker></date>).
  2. An attribute on an element (<input type="text" date-picker/>).
  3. As a class (<input type="text" class="date-picker"/>).
  4. As comment (<!--directive:date-picker-->).

Of course, we have control over how our directive will appear in the HTML. Now, let’s see how a typical directive is written in Angular. It is registered in the same way as a controller, but it returns a simple object (directive definition) that has several properties to configure the directive. The following code shows a simple Hello World directive.

1
2
3
4
5
6
7
8
9
var app = angular.module('myapp', []);
app.directive('helloWorld', function() {
  return {
      restrict: 'AE',
      replace: 'true',
      template: '<h3>Hello World!!</h3>'
  };
});

In the previous code, the app.directive() function registers a new directive in our module. The first argument to this function is the directive name. The second argument is a function which returns a directive definition object. If your directive has dependencies on external objects/services such as $rootScope,$http, or $compile, they can be injected here. The directive can be used in HTML as an element like this:

1
<hello-world/>

Or:

1
<hello:world/>

Or, as an attribute like this:

1
<div hello-world></div>

Or:

1
<div hello:world/>

Note:

While matching directives, Angular strips the prefix x- or data- from element/attribute names. Then it converts - or : delimited strings to camelCase and matches with the registered directives. That’s why we have used the helloWorld directive as hello-world in the HTML.

Though the above directive does nothing more than show static text, we have some interesting points to explore. We have used three properties in the directive definition object to configure the directive. Let’s explore the role that each one plays.

  • restrict – This provides a way to specify how a directive should be used in HTML (remember a directive can appear in four ways). In this case we have set it to 'AE'. So, the directive can be used as a new HTML element or an attribute. To allow this directive to be used as a class we can set restrict to'AEC'.
  • template – This specifies the HTML markup that will be produced when the directive is compiled and linked by Angular. This does not have to be a simple string. The template can be complex, often involving other directives, expressions ({{ }}), etc. In most cases you want to use templateUrlinstead of template. So, ideally you should place the template in a separate HTML file and maketemplateUrl point to it.
  • replace – This specifies if the generated template will replace the HTML element on which the directive is attached. In our case we have used the directive as <hello-world></hello-world>, and replace is set to true. So, after the directive is compiled, the produced output template replaces <hello-world></hello-world>. The final output is <h3>Hello World!!</h3>. If you set replace to false, the default, the output template will be inserted into the element on which the directive is invoked.

Open up this plunker, right click on “Hello World!!”, and do an inspect element to visualize things.

The link Function and Scope

The template produced by a directive is meaningless unless it’s compiled against the right scope. By default a directive does not get a new child scope. Rather, it gets the parent’s scope. This means that if the directive is present inside a controller it will use that controller’s scope.

To utilize the scope, we can make use of a function called link. This is configured by the link property of the definition object. Let’s change our helloWorld directive so that when the user types a color name into an input field, the background color of Hello World text changes automatically. Also, when a user clicks on the text Hello World, the background color should reset to white. The HTML markup is shown below.

1
2
3
4
<body ng-controller="MainCtrl">
  <input type="text" ng-model="color" placeholder="Enter a color" />
  <hello-world/>
</body>

The modified helloWorld directive is shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
app.directive('helloWorld', function() {
  return {
    restrict: 'AE',
    replace: true,
    template: '<p style="background-color:{{color}}">Hello World',
    link: function(scope, elem, attrs) {
      elem.bind('click', function() {
        elem.css('background-color', 'white');
        scope.$apply(function() {
          scope.color = "white";
        });
      });
      elem.bind('mouseover', function() {
        elem.css('cursor', 'pointer');
      });
    }
  };
});

Notice the link function used in the directive. It takes three arguments:

  • scope – The scope passed to the directive. In this case it’s the same as the parent controller scope.
  • elem – The jQLite (a subset of jQuery) wrapped element on which the directive is applied. If you have included jQuery in the HTML before AngularJS is included, this becomes jQuery wrapped instead of jQLite. As the element is already wrapped with jQuery/jQLite, there is no need to again wrap it inside $() for DOM manipulations.
  • attrs – An object representing normalized attributes attached to the element on which the directive is applied. For example, you can attach attributes in HTML like: <hello-world some-attribute></hello-world> and access it in the link function as attrs.someAttribute.

The link function is mainly used for attaching event listeners to DOM elements, watching model properties for changes, and updating the DOM. In the previous directive snippet, we attached two listeners, click andmouseover. The click handler resets the background color of the <p>, while the mouseover handler changes the cursor to pointer. The template has an expression {{color}} which changes whenever the model color changes in the parent scope, thereby changing the background color of Hello World. Here is aplunker demonstrating this concept.

http://www.sitepoint.com/practical-guide-angularjs-directives/

Advertisements

Angularjs – Directives

What are Directives?

At a high level, directives are 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 or even transform the DOM element and its children.

Matching Directives

Before we can write a directive, we need to know how Angular’s HTML compiler determines when to use a given directive.

$compile can match directives based on element names, attributes, class names, as well as comments.

All of the Angular-provided directives match attribute name, tag name, comments, or class name. The following demonstrates the various ways a directive (myDir in this case) can be referenced from within a template:

<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>

Template-expanding directive

Let’s say you have a chunk of your template that represents a customer’s information. This template is repeated many times in your code. When you change it in one place, you have to change it in several others. This is a good opportunity to use a directive to simplify your template.

Let’s create a directive that simply replaces its contents with a static template:

Script.js:

angular.module('docsSimpleDirective', [])
  .controller('Controller', ['$scope', function($scope) {
    $scope.customer = {
      name: 'Naomi',
      address: '1600 Amphitheatre'
    };
  }])
  .directive('myCustomer', function() {
    return {
      template: 'Name: {{customer.name}} Address: {{customer.address}}'
    };
  });
index.html:
<div ng-controller="Controller">
  <div my-customer></div>
</div>

Great! But what if we wanted to have our directive match the tag name <my-customer> instead? If we simply put a <my-customer>element into the HTML, it doesn’t work.

Note: When you create a directive, it is restricted to attribute only by default. In order to create directives that are triggered by element or class name, you need to use the restrict option.

The restrict option is typically set to:

  • 'A' – only matches attribute name
  • 'E' – only matches element name
  • 'C' – only matches class name

These restrictions can all be combined as needed:

  • 'AEC' – matches either attribute or element or class name

Let’s change our directive to use restrict: 'E':

Script.js:

angular.module(‘docsRestrictDirective’, [])
.controller(‘Controller’, [‘$scope’, function($scope) {
$scope
.customer = {
name
: ‘Naomi’,
address
: ‘1600 Amphitheatre’
};
}])
.directive(‘myCustomer’, function() {
return {
restrict
: ‘E’,
templateUrl
: ‘my-customer.html’
};
});

index.html

<div ng-controller="Controller">
  <my-customer></my-customer>
</div>

my-customer.html

Name: {{customer.name}} Address: {{customer.address}}

More: https://docs.angularjs.org/guide/directive