Angular Custom Attribute Directive Example
January 03, 2021
This page will walk through Angular 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.
Contents
- Technologies Used
- Project Structure
- Simple Attribute Directive
- Attribute Directive using @Input()
- Attribute Directive using Multiple @Input()
- Attribute Directive using @HostListener() to listen Event
- Attribute Directive using @Input() and @HostListener()
- Application Component and Module
- Run Application
- Reference
- Download Source Code
Technologies Used
Find the technologies being used in our example.1. Angular 11.0.3
2. Node.js 12.5.0
3. NPM 6.9.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'; } }
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 { }
<p myRed> myRed Directive Demo</p>
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'; } }
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>
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; } }
@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>
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';
Case-1: Directive name and
@Input()
property name are different with no alias.
@Input() tsize: string;
<p textSize tsize="{{txtsize}}"> textSize Directive Demo using Bracket []</p>
@Input()
property name to take user input.
Case-2: Directive name and
@Input()
property name are same with no alias.
@Input() textSize: string;
<p [textSize]="txtsize"> textSize Directive Demo using Bracket []</p>
@Input()
alias are same. No matter what is @Input()
property name.
@Input('textSize') tsize: string;
<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; } }
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; } }
<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; } }
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>
colors
and myColor
are the properties defined in our component.
colors = ['CYAN', 'GREEN', 'YELLOW']; myColor = '';
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.tsimport { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { txtsize = '25px'; colors = ['CYAN', 'GREEN', 'YELLOW']; myColor = ''; }
<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>
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 { }
Run Application
To run the application, find the steps.1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
Find the print screen of the output.
