Understand Directive In Angular 2

Introduction

Directives are one of the most important features of AngularJS applications. They are extended HTML attributes. In other words, directives are something that introduce new syntax / markup. They are markers on the DOM element which provides some special behavior to DOM elements and tells AngularJS's HTML compiler to attach.

There are three kinds of directives in an Angular 2 application.

  1. Components
    Angular Component also refers to a directive with a template which deals with View of the Application and also contains the business logic. It is very useful to divide your Application into smaller parts. In other words, we can say that Components are directives that are always associated with the template directly.

  2. Structural directives
    Structural directives are able to change the behavior of DOM by adding and removing DOM elements. The directive NgFor, NgSwitch, and NgIf is the best example of structural directives.

  3. Attribute directives
    Attribute directives are able to change the behavior of DOM. The directive NgStyle is an example of Attribute directives which are used to change styles elements at the same time.

Directive Lifecycle

Same as the Component, Angular managed directive lifecycle by itself. Angular is able to create and render the directive. It also updates data when the associated model is changed and Angular destroys the directives before removing from the DOM.

Angular directives lifecycle hooks provide us visibility into the important moments and we can do some custom activity when they are raised. Angular will call lifecycle hook only if it is defined.

Following are the life cycle sequences for directive.

Name of event (hook) Description
ngOnChanges It occurs when Angular sets data bound property. Here, we can get current and previous value of changed object. It is raised before the initialization event for directive.
ngOnInit It occurs after Angular initializes the data-bound input properties.
ngDoCheck It is raised every time when Angular detects any change.
ngOnDestroy It is used for cleanup purposes and it is raised just before Angular destroys the directive. It is very much important in memory leak issues by un-subscribing observables and detaching event handlers.

 life cycle sequence for directive

Attribute / Structural directive Vs Component directive

Following are the differences between component directive and Attribute / Structural directive.

Attribute / Structural Directive Component directive
They are used to create behavior to an existing DOM element. It used to shadow DOM to create encapsulates visual behavior. It is used to create UI widgets.
They help us to create re-usable components It helps us to break up our application in smaller component
We cannot create pipes using Attribute / Structural directive Pipes can be defined by component
We can define many directive per DOM element We can present only one component per DOM element
@directive keyword is used to define metadata @component keyword is used to define metadata

Example

In this example, I have created a directive that changes the style (makes it bold) of the text when mouse is hovered on the text and text becomes normal when cursor is removed.

To write the directive, we begin with importing symbols like Directive, ElementRef, HostListener and Renderer from the Angular Core. With the help of symbol "Directive", we can use decorator "@Directive" in our code. Similarly, the symbol "ElementRef" is required to inject directive's constructor, symbol "HostListener" is required to use @HostListener decorator. The @HostListener decorator refers to the DOM element and we have to attached event listeners by manipulating the host DOM element directly and symbol "Renderer" is required for accessing element’s properties such as style. After importing symbols, we need to define metadata for the directive using @Directive decorator. The @Directive needs a selector to identify the HTML in the template that is associated with the directive.

Lastly, I have exported the directive class and I write two event listeners, one for "onMouseEnter" and other for "onMouseLeave". I have changed the style of the element within these events.

Following is the code for the directive in TypeScript.

mydirective.ts

  1. import { Directive, ElementRef, HostListener,  Renderer } from '@angular/core';  
  2. @Directive({  
  3.   selector: '[myFirstDirective]'  
  4. })  
  5. export class MyFirstDirective {  
  6.   constructor(private el: ElementRef, private renderer: Renderer) { }  
  7.     
  8.   @HostListener('mouseenter') onMouseEnter() {  
  9.     this.makeItBold(true);  
  10.   }  
  11.     
  12.   @HostListener('mouseleave') onMouseLeave() {  
  13.     this.makeItBold(false);  
  14.   }  
  15.   private makeItBold(inputValue: boolen) {  
  16.     if(inputValue)  
  17.         this.renderer.setElementStyle(this.el.nativeElement, 'font-weight''bold');  
  18.     else  
  19.         this.renderer.setElementStyle(this.el.nativeElement, 'font-weight''normal');  
  20.   }  
  21. }  
If we want to use directives, we need to import this directive into that class and also, define in "declarations" part of metadata. So that, Angular can recognize the directive and add new behavior to the DOM element.

Following is the code for Module in which we have imported the directive and its components use this directive for the TypeScript.

app.module.ts
  1. import { NgModule }      from '@angular/core';  
  2. import { BrowserModule } from '@angular/platform-browser';  
  3.   
  4. import { AppComponent }  from './app.component';  
  5. import { MyFirstDirective } from './mydirective';  
  6.   
  7. @NgModule({  
  8.   imports:      [ BrowserModule],  
  9.   declarations: [ AppComponent, MyFirstDirective ],  
  10.   bootstrap:    [ AppComponent ]  
  11. })  
  12. export class AppModule {   
  13. }  
The Component uses this newly created directive. Following is the code for the component used by this example.

app.component.ts
  1. import { Component } from '@angular/core';  
  2. @Component({  
  3.   selector: 'test-app',  
  4.   template: '<h4>Directive in Angular 2 Application</h4>' +  
  5.             '<p myFirstDirective>Hello C# Corner!</p>'  
  6. })  
  7. export class AppComponent {   
  8. }  
Output

When we run the app, we can see that our directive makes the paragraph text bold when mouse enters into the text area and the paragraph text becomes normal when mouse leaves from there.

Output

Summary

Directives are very useful for extending HTML and they help us create re-usable components.