Custom Attribute Directive In Angular

If you are new to Directive then I have already explained about directives in my previous article, Directives in Angular 5, please go through it before you continue reading.
 
Now, we knew all about built-in directives, it’s a time to control the behavior of DOM elements. So, we create our own directives.
 
To create custom directives we need to learn only three steps, they are:
  1. Create a directive
  2. Register it.
  3. Use it into View
Step 1 - Create a Directive

Let's understand how to create a new custom directive. We do create a directive which simply highlights an element whenever the mouse hovers over it.

For this, we create a new folder called “directives”. In this folder, we create a file called “element-highlight.directive.ts” file. Inside the file, write the below code,
  1. import { element } from 'protractor';  
  2. import { Directive, OnInit, ElementRef } from "@angular/core";  
  3.   
  4. @Directive({  
  5.    selector:'[elementHighlight]'  
  6. })  
  7.   
  8. export class ElementHighlightDirective implements OnInit{  
  9.    constructor( private eleRef:ElementRef){}  
  10.    ngOnInit(){  
  11.        this.eleRef.nativeElement.style.backgroundColor='red';  
  12.        this.eleRef.nativeElement.style.color='white';  
  13.    }  
  14. }  
In the above code, @Directive is a decorator function which is imported from ‘@angular/core’ library. Inside the directive, we have used ‘selector’ property just like as we used in component, now set the value of selector with string enclosed in square bracket []. Basically, this value is our directive name, that we will use in our template.
 
After that we create an object (eleRef) of type ElementRef, to access those elements on which we want to apply this directive (i.e. DOM element). Now, inside the ngOnInit(), we change the style of that element.
 
Step 2 - Register Directive
 
Now, it’s time to register and use the directive. As per step 2, we need to register our directive before use. For this, go to “app.module.ts” file. In this file, first of all, import your directive like 
  1. import { ElementHighlightDirective } from './directives/element-highlight.directive';  
After that inside the @NgModule, go to the declaration part and write the class name, like this: 
  1. declarations: [  
  2.     AppComponent,  
  3.     ElementHighlightDirective  
  4.   ],  
Step 3 - Use it in View
 
Now, as per our third step, we are going to use this directive in our template. So, for this open your "app.component.html" file and put in the below code:
  1. <div style="text-align:center">  
  2.   <h1>  
  3.     Custom Directive  
  4.   </h1>  
  5.  </div>  
  6.  <div class="row">  
  7.   <p elementHighlight>Mahesh Verma</p>  
  8.  </div>  

Now, save and run the project and see the output.

Angular

After seeing the above output, we can say that our directive is working.

Use of @HostListner in Directives
 
Now, we have learned about a basic and simple directive. It’s time to handle some DOM events where directives can be implemented. For this, we require something which can handle these DOM events. Angular provides @HostListner decorator function for that.
If we want to handle DOM events like focus, blur, mouseover, mouseleave, mouseenter etc, then we need to listen to them and for listening we use @HostListner. This decorator allows us to subscribe to the raised events from the DOM elements.
 
Let’s understand it with an example.

Suppose, in the directive we want that whenever we hover the mouse over the div then its color changes into red, and when the mouse leaves it again it looks simple, then we use two events (mouseenter and mouseleave) with the help of @HostListner.
 
Change the code into “element-highlight.directive.ts” file as per the below code,
  1. export class ElementHighlightDirective implements OnInit{  
  2.     constructor( private eleRef:ElementRef){}  
  3.     ngOnInit(){  
  4.     }  
  5.     @HostListener('mouseover') mouseover(eventData:Event){  
  6.         this.eleRef.nativeElement.style.backgroundColor="Red";  
  7.         this.eleRef.nativeElement.style.color="White";  
  8.     }  
  9.    
  10.     @HostListener('mouseleave') mouseleave(eventData:Event){  
  11.         this.eleRef.nativeElement.style.backgroundColor="transparent";  
  12.         this.eleRef.nativeElement.style.color="Black";  
  13.     }  
  14.  }  
With the help of @HostListner, Angular listened to these two events ‘mouseover’ and ‘mouseleave’, where the directive had been implemented. See the output, there is no need to change into app.component.html file.
 
Angular
 
Use of @HostBinding in Directives 
 
Let’s understand about one more decorator function called @HostBinding. Now, if we want to change the style properties, such as height, width, color, border etc., we need to use the @HostBinding() decorator function to access these properties on the host element and assign a value to it in directive class.

In this function, we can pass only one string defining to which property of the hosting element we want to bind or, we can say, decorator, takes one parameter i.e. the name of the host element property whose value we want to assign in the directive.

Let’s understand with the help of an example, we can achieve the above-mentioned feature by making changes in directive property and binding it with HostBinding.

Change the directive code as following,
  1. export class ElementHighlightDirective implements OnInit{  
  2.     constructor( private eleRef:ElementRef){}  
  3.     ngOnInit(){  
  4.     }  
  5.    
  6.  @HostBinding('style.backgroundColor')backgroundColor:string="transparent";  
  7.    
  8.     @HostListener('mouseover') mouseover(eventData:Event){  
  9.         this.backgroundColor="Red";  
  10.         this.eleRef.nativeElement.style.color="White";  
  11.     }  
  12.    
  13.     @HostListener('mouseleave') mouseleave(eventData:Event){  
  14.         this.backgroundColor="transparent";  
  15.         this.eleRef.nativeElement.style.color="Black";  
  16.     }  
  17.  }  
In the above code, we set “backgroundColor” as a string with HostBinding, and inside the HostBinding decorator function we passed “style.backgroundColor”, now whenever we will change our string i.e. “backgroundColor”, it changes the style of host element where we had implemented the directive. If we save and run the above code, then output will be the same as the above one.
 
After getting so much information about directives, now a question arises:

Can we pass data from directives?

So, the answer is Yes, we can pass the data from directives by using the binding property and @Input(). Let’s understand this with the help of an example.

Go to the “element-highlight.directive.ts” and change directive as per the following code,
  1. export class ElementHighlightDirective {  
  2.    
  3.     @Input() defaultColor:string="";  
  4.     @Input() highlightColor:string="";  
  5.      
  6.  @HostBinding('style.backgroundColor') backgroundColor:string=this.defaultColor;  
  7.    
  8.     constructor( private eleRef:ElementRef){}  
  9.     
  10.     @HostListener('mouseover') mouseover(eventData:Event){  
  11.         this.backgroundColor=this.highlightColor;  
  12.         this.eleRef.nativeElement.style.color="White";  
  13.     }  
  14.    
  15.     @HostListener('mouseleave') mouseleave(eventData:Event){  
  16.         this.backgroundColor=this.defaultColor;  
  17.         this.eleRef.nativeElement.style.color="Black";  
  18.     }  
  19.  }  
In the above code we declared two input properties called “defaultColor” and “highlightColor” and set the value of these properties on “mouseover” and “mouseleave” events.

Now, pass the value of these properties from directive:
  1. <div class="row">  
  2. <p elementHighlight [defaultColor]="'transparent'" [highlightColor]="'Red'">Mahesh Verma</p>  
  3. </div>  

Save and run the project, the output is:

Angular
 
Format Credit Card Number using Custom Directive
 
I hope you have learned all the basic concepts of directive, let’s create one more useful directive, like, a directive which will accept a value from textbox and convert it into credit card format, i.e. with the help of directive put dash (‘-’) after each 4 digits, like someone enter “1234987609876543” then it converted into “1234-9876-0987-6543”.

For this write the following code into your “element-highlight.directive.ts”
  1. export class ElementHighlightDirective {  
  2.     constructor(private eleRef: ElementRef) { }  
  3.     @HostListener('blur') blur(eventData: Event) {  
  4.         let val: string = "";  
  5.         val = this.eleRef.nativeElement.value;  
  6.         if (val.length > 0) {  
  7.           val = val.match(new RegExp('.{1,4}''g')).join('-');  
  8.          }  
  9.         this.eleRef.nativeElement.value = val;  
  10.     }  
  11.  }  
Now, go to the “app.component.html” file and write the below code
  1. <div class="row">  
  2.   <input type="text" placeholder="Enter any number" elementHighlight />  
  3. </div>  
See, the output of the above code
 
Angular
 
Note
In the above code, we have not applied any kind of validation or other things, we can modify as per our requirements, here we got to know how we can use directives.
 
Conclusion

As we know, directives are a very important concept in Angular and most of the time we need to create directives as per our requirement. I hope you have learned something about custom directives from this article. For practice purposes, I have attached a sample project called “CustomSampleDirectives” which covers all the code. You can download and modify this as per your requirement. All your queries related to this article and sample project are always welcomed. Thanks for reading.