Angular Custom Directives

What is a Directive?

Angular directives are extended HTML attributes with the prefix ng-. They are what makes Angular so powerful and responsive. The ng-app directive initializes an Angular application. The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

Even though Angular is full of useful directives, often times we want to create our own customized reusable directives. We will start with building a simple directive and explain the process.

How does directives work?

Angular enables us to create new directives that we can encapsulate and perform DOM manipulation. We can create directives that modify or even create totally new behavior in HTML.

The ng-app attribute is a directive, so is ng-controller and all of the ng- prefixed attributes.

Angular will traverse the DOM elements looking for any directives that are associated with each DOM element. Once it’s found all of it/them, it will then start running the directive and associating it with the DOM element. This all happens behind the scenes and automatically for you.

  <div ng-app>
    <label for="name">Type your name</label>
    <input type="text" ng-model="name"
      placeholder="name" id="name">
      <p>{{ name }}</p>
  </div>
Try:

{{ name }}

Invoking a directive

To invoke a directive from HTML, we simply can apply the directive in the DOM.

There are four methods for invoking a directive:

  1. As an attribute
  2. As a class
  3. As an element
  4. As a comment

As an attribute:

  <span my-directive></span>

As a class:

  <span class="my-directive: expression;"></span>

As an element:

  <my-directive></my-directive>

As a comment:

  <!-- directive: my-directive expression -->

Here are some examples of Angular invoking directives:

  <input type="text" ng-model="directivename" />
  <span ng-bind="directivename"></span>
  <span ng:bind="directivename"></span>
  <span ng_bind="directivename"></span>
  <span x-ng-bind="directivename"></span>
  <span data-ng-bind="directivename"></span>

Building a directive

Let’s create a simple Angular directive.

  app.directive('myDirective', function() {
    return {
      restrict: 'A',
      template: '<div class="sparkline"></div>'
    }
  });

And invoke it in our html:

  <div my-directive></div>

Notice, when we invoked the directive it isn’t the same as name as when we defined it. This is because AngularJS will handle translating the camel cased name when we define it to the snake case when we invoke it.

Restrict option

The restrict option is used to specify how a directive can be invoked on the page.

  'A' - <span ng-sparkline></span>
  'E' - <ng-sparkline></ng-sparkline>
  'C' - <span class="my-directive"></span>
  'M' - <!-- directive: my-directive -->

The restrict option can specify multiple options as well.

  restrict: 'EA',

Template

Template is an inline template where we are specifying the html that will be appended or replaced. This is particularly useful when we want to share directives across apps and you only want to pass a single file around.

TemplateUrl

If you prefer to load a template over ajax, you can specify the templateUrl option.

  templateUrl: 'templates/my-directive-template.html'

Scope

Directives can be given their own scope like the other parts of the Angular DOM.

Angular gives you the ability to isolate the scope of the directive from the rest of the page using the scope option.

When the scope directive is set to true, a new scope will be created for the directive.

  scope: true,
Isolate Scope

We can isolate the directive’s scope outside of the parent relationship by creating an isolate scope.

An isolate scope does not prototypically inherit from the parent scope, but creates an entirely new one. Creating this isolate scope will ensure that your directive does not mess with the existing scope.

To create an isolate scope, simply pass an object back in the scope option:

  scope: {}

This will create an empty scope. This is not particularly useful because your directive will have nothing available on its scope (other than the variables that you manually add).

To make local variables on your local scope available to the new directive’s scope, you’ll have to pass one of the following three aliases in the object:

  1. Local scope property
  2. Bi-directional binding
  3. Parent execution binding
Local scope property

To bind a local scope (string) to the value of the DOM attribute, use the @symbol. Now the value of the outer scope will be available inside your directive’s scope:

  @
Bi-directional binding

A bi-directional binding between the local scope property and the parent property can be done using the = symbol. If the parent model changes, the local property will reflect the change.

  =
Parent execution binding

To bind to the parent scope, use the & symbol.

  &

Let’s look at an example on how to implement these bindings:

my-directory source:

  app.directive('my-directive', function() {
    return {
      restrict: 'A',
      require: '^ngModel',
      scope: {
        myOtherDirectory: '@'
      },
      template: '<div class="my-directive"><p>Info: {{ngModel}}</p></div>'
    }
  });

html source:

  <div my-directory my-other-directory="My Other Directory"></div>

my-other-directory source:

  app.directive('myOtherDirectory', function() {
    return {
      controller: function($scope) {}
    }
  });

Be first to comment

Leave a Reply