Home  >  Angular

Angular 2 Custom Attribute Directive Example

By Arvind Rai, April 28, 2017
This page will walk through angular 2 custom attribute directive example. Angular provides three types of directive: component directive, attribute directive and structural directive. Component directive is used to create HTML template. This is most commonly used directive in angular project. Attribute directive changes the appearance or behavior of DOM element. Structural directive is used to change the DOM layout by adding and removing DOM elements. Angular provides in-built structural directive such as NgFor and NgIf. Angular also provides in-built attribute directive such as NgStyle. We can create custom attribute directives and custom structural directives using @Directive decorator. Using custom attribute directive we can change appearance such as text color, background color and font size of body of an HTML element that can be called host element. To change appearance angular provides ElementRef class that can directly access DOM. It is vulnerable to XSS attacks when we directly use ElementRef in our application. It is better to create a custom directive and use ElementRef inside directive to change appearance or behavior of the host element.
Find the steps to create custom attribute directive.
1. Create a class decorated with @Directive.
2. Assign the attribute directive name to the selector metadata of @Directive decorator.
3. Use ElementRef class to access DOM to change host element appearance and behavior.
4. Use @Input() decorator to accept user input in our custom directive.
5. Use @HostListener() decorator to listen events in custom attribute directive.
6. Configure custom attribute directive class in application module in the declarations metadata of @NgModule.

Now we will provide a complete example of custom attribute directive. We will create different custom attribute directive for different scenarios. Let us start now.

Software Used

Find the software used in our example.
1. Angular 4.0.0
2. TypeScript 2.2.0
3. Node.js 6.10.1
4. Angular CLI 1.0.0
5. Angular Compiler CLI 4.0.0

Project Structure

Find the project structure.
angular-demo
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--directives
|   |   |   |
|   |   |   |--color-input.directive.ts
|   |   |   |--custom-theme.directive.ts
|   |   |   |--dynamic-color.directive.ts
|   |   |   |--mouse.directive.ts
|   |   |   |--red.directive.ts
|   |   |   |--text-size.directive.ts
|   |   |   |--theme.directive.ts
|   |   |
|   |   |--app.component.ts
|   |   |--app.component.html
|   |   |--app.module.ts 
|   | 
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json 

Simple Attribute Directive

Here we will create two simple custom attribute directive.

1. Attribute directive to change text color of HTML Element

We will start creating attribute directive with a simple example. We are creating a directive named as myRed directive. When we will use it with HTML element such as <p> and <div>, the text color within that element will be red. Find the code.
red.directive.ts
import { Directive, ElementRef } from '@angular/core';

@Directive({ 
     selector: '[myRed]' 
})
export class MyRedDirective {
    constructor(elRef: ElementRef) {
       elRef.nativeElement.style.color = 'red';
    }
} 
Let us understand step by step.
1. The class should be decorated with @Directive. The role of @Directive is to mark a class as an angular directive and to collect directive configuration metadata.
2. To define a directive name, we need to use metadata selector and assign a directive name enclosed with bracket [ ], for example [myRed]. We should not use any keyword as directive name which is reserved by angular and we should also not start directive name with ng .
3. Create constructor in the class to get the instance of ElementRef by dependency injection. Using ElementRef we can access DOM element and can change their appearance and behavior.
4. To use our custom directive anywhere in our angular application, we need to configure it in application module in the same way as we configure component.
import { MyRedDirective }  from './directives/red.directive';

@NgModule({
----------------
----------------
  declarations: [
        ---------
        ---------
	MyRedDirective
        ---------
        ---------
  ]
----------------
----------------
})
export class AppModule { } 
Now we are ready to use our directive in the HTML template. Find the code snippet.
<p myRed> myRed Directive Demo</p> 
The text will be displayed as red.

2. Attribute directive to change text color, background color and font size of HTML Element

We will create a custom attribute directive that will change text color, background color and font size. To change the HTML attribute we need to use ElementRef that has the property nativeElement and using it we can change HTML attribute of an element in the DOM. Find the code.
theme.directive.ts
import { Directive, ElementRef } from '@angular/core';

@Directive({ 
     selector: '[niceTheme]' 
})
export class NiceThemeDirective {
    constructor(elRef: ElementRef) {
       elRef.nativeElement.style.color = '#00cc66';
       elRef.nativeElement.style.backgroundColor = '#ccccff';
       elRef.nativeElement.style.fontSize = '20px';
    }
} 
Before using the niceTheme attribute directive, we need to configure NiceThemeDirective class in application module in the declarations block of @NgModule. Now we are ready to use niceTheme directive as follows.
<div niceTheme> niceTheme Directive Demo</div> 

Attribute Directive using @Input()

To take user input in custom directive, we need to create a property decorated with @Input(). We will create a myColor directive that will take user input color name in HTML template.
color-input.directive.ts
import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core';

@Directive({ 
     selector: '[myColor]' 
})
export class ColorInputDirective implements AfterViewInit{
    @Input() inputColor: string;
    constructor(private elRef: ElementRef) { 
    }
    ngAfterViewInit(): void {
	this.elRef.nativeElement.style.color = this.inputColor;
    }
}
AfterViewInit: It is the lifecycle hook that is called after a component view has been fully initialized. To use AfterViewInit, our class will implement it and override its method ngAfterViewInit().

Now in HTML template we can use myColor directive as given below.
<div myColor inputColor="blue"> myColor Directive Demo</div> 
Find one more example. Here we will create a directive named as textSize. It will take user input text size.
text-size.directive.ts
import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core';

@Directive({ 
     selector: '[textSize]' 
})
export class TextSizeDirective implements AfterViewInit{
    @Input('textSize') tsize: string;
    constructor(private elRef: ElementRef) { 
    }
    ngAfterViewInit(): void {
	this.elRef.nativeElement.style.fontSize = this.tsize;
    }
} 
If directive name is same as @Input() alias or property name, then we use our directive in HTML template as given below.
<p [textSize]="txtsize"> textSize Directive Demo using Bracket []</p>
<p bind-textSize="txtsize"> textSize Directive Demo using bind- prefix  </p>
<p textSize="{{txtsize}}"> textSize Directive Demo using Interpolation</p> 
We know that attribute directive can be used using bracket [ ], prefix bind- and interpolation.

By above two directive myColor and textSize, we observe different scenarios in using @Input(). Suppose we are using directive name as selector: '[textSize]' and we have a variable in our component as given below.
txtsize = '25px'; 
Then find the following cases.
Case-1: Directive name and @Input() property name are different with no alias.
@Input() tsize: string; 
So we use directive as given below.
<p textSize tsize="{{txtsize}}"> textSize Directive Demo using Bracket []</p> 
Use directive name and @Input() property name to take user input.
Case-2: Directive name and @Input() property name are same with no alias.
@Input() textSize: string; 
Now we can bind attribute directive as given below.
<p [textSize]="txtsize"> textSize Directive Demo using Bracket []</p> 
Case-3: Directive name and @Input() alias are same. No matter what is @Input() property name.
@Input('textSize') tsize: string; 
Again we can use attribute directive as given below.
<p [textSize]="txtsize"> textSize Directive Demo using Bracket []</p> 

Attribute Directive using Multiple @Input()

Here we will create an attribute directive that will accept more than one user input. To accept more than one user input, we need to use more than one @Input() decorated property in our class. Find the code.
custom-theme.directive.ts
import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core';

@Directive({ 
     selector: '[customTheme]' 
})
export class CustomThemeDirective implements AfterViewInit {
    @Input() tcolor: string;
    @Input() bcolor: string;
    @Input() tsize: string;	
    constructor(private elRef: ElementRef) {
    }
    ngAfterViewInit(): void {
	   this.tcolor = this.tcolor || 'green';
	   this.bcolor = this.bcolor || 'cyan';
	   this.tsize = this.tsize || '20px';
           this.elRef.nativeElement.style.color = this.tcolor;
	   this.elRef.nativeElement.style.backgroundColor = this.bcolor;
	   this.elRef.nativeElement.style.fontSize = this.tsize;
    }	
} 
We will use customTheme directive as follows.
<div customTheme> customTheme Directive Demo with Default Settings</div>
<div customTheme tcolor="yellow" bcolor="black" tsize="30px"> customTheme Directive Demo with Custom Settings</div> 

Attribute Directive using @HostListener() to listen Event

We can create custom attribute directive that will perform changes in appearance in DOM when an event is fired. To listen any event we need to use @HostListener() decorator. We need to assign event name to @HostListener() decorator. Here we will create an attribute directive that will change background color of host element when mouseover and mouseleave events are fired. Find the code.
mouse.directive.ts
import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({ 
     selector: '[mouseAction]' 
})
export class MouseActionDirective {
   constructor(private elRef: ElementRef) { 
   }
   @HostListener('mouseover') onMouseOver() {
     this.changeBackgroundColor('darkgrey');
   }
   @HostListener('mouseleave') onMouseLeave() {
     this.changeBackgroundColor('white');
   }
   private changeBackgroundColor(color: string) {
     this.elRef.nativeElement.style.backgroundColor = color;
   }  
} 
Find the HTML template.
<p mouseAction> mouseAction Directive Demo</p> 

Attribute Directive using @Input() and @HostListener()

We will create attribute directive that will accept user input as well listen events. The role of @Input() decorator is to accept user input and the role of @HostListener() decorator is to listen event. Here we will create attribute directive named as dynamicColor. It will accept two inputs for background color. Second input color will be default color and will be active if first input color has not been given. Now find the code.
dynamic-color.directive.ts
import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({ 
     selector: '[dynamicColor]' 
})
export class DynamicColorDirective {
   @Input('dynamicColor') dynamicColor: string;
   @Input() defaultValue: string;
   constructor(private elRef: ElementRef) {
   }
   @HostListener('mouseover') onMouseOver() {
     this.changeBackgroundColor(this.dynamicColor || this.defaultValue);
   }
   @HostListener('mouseleave') onMouseLeave() {
     this.changeBackgroundColor('white');
   }
   private changeBackgroundColor(color: string) {
     this.elRef.nativeElement.style.backgroundColor = color;
   }  
} 
The background color of text of host element can be selected from a select box and when the mouse event mouseover is fired, background color will be displayed as selected in select box. When mouseleave event is fired, a fixed color white will be displayed. Find the code snippet.
<div>
  <select [(ngModel)] ="myColor">
    <option value='' selected> Select Color </option>
    <option *ngFor = "let color of colors" [value] = "color">
		{{color}}
    </option>
  </select>
<p [dynamicColor]="myColor" defaultValue="red"> dynamicColor Directive Demo</p>
</div> 
In the above code colors and myColor are the properties defined in our component.
colors = ['CYAN', 'GREEN', 'YELLOW'];
myColor = ''; 
When we select no color, the color assigned to defaultValue will be active and when we select any color from the select box then that color will be active.

Application Component and Module

app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   templateUrl: './app.component.html'
})
export class AppComponent { 
   txtsize = '25px';
   colors = ['CYAN', 'GREEN', 'YELLOW'];
   myColor = '';
} 
app.component.html
<p myRed> myRed Directive Demo</p>

<div niceTheme> niceTheme Directive Demo</div>

<div myColor inputColor="blue"> myColor Directive Demo</div>

<p [textSize]="txtsize"> textSize Directive Demo using Bracket []</p>

<p bind-textSize="txtsize"> textSize Directive Demo using bind- prefix  </p>

<p textSize="{{txtsize}}"> textSize Directive Demo using Interpolation</p>

<div customTheme> customTheme Directive Demo with Default Settings</div>

<div customTheme tcolor="yellow" bcolor="black" tsize="30px"> customTheme Directive Demo with Custom Settings</div>

<p mouseAction> mouseAction Directive Demo</p>

<div>
  <select [(ngModel)] ="myColor">
    <option value='' selected> Select Color </option>
    <option *ngFor = "let color of colors" [value] = "color">
		{{color}}
    </option>
  </select>
<p [dynamicColor]="myColor" defaultValue="red"> dynamicColor Directive Demo</p>
</div> 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }        from '@angular/forms';

import { AppComponent }  from './app.component';
import { MyRedDirective }  from './directives/red.directive';
import { NiceThemeDirective }  from './directives/theme.directive';
import { CustomThemeDirective }  from './directives/custom-theme.directive';
import { ColorInputDirective }  from './directives/color-input.directive';
import { TextSizeDirective }  from './directives/text-size.directive';
import { MouseActionDirective }  from './directives/mouse.directive';
import { DynamicColorDirective }  from './directives/dynamic-color.directive';

@NgModule({
  imports: [     
        BrowserModule,
	FormsModule
  ],
  declarations: [
        AppComponent,
	MyRedDirective,
	NiceThemeDirective,
	CustomThemeDirective,
	ColorInputDirective,
	TextSizeDirective,
	MouseActionDirective,
	DynamicColorDirective
  ],
  bootstrap: [
        AppComponent
  ]
})
export class AppModule { } 

Test Application

To test the application, find following steps.
1.: Download source code using download link given on this page.
2.: In our angular CLI application, replace src folder.
3.: Run ng serve command.
4.: Now access the URL http://localhost:4200 . Find the print screen.
Angular 2 Custom Attribute Directive Examples


Now I am done. Happy Angular 2+ Learning!

Reference

ATTRIBUTE DIRECTIVES

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
FIND MORE TUTORILAS


©2019 concretepage.com | Privacy Policy | Contact Us