An angular directive is instructions or guidelines for rendering a template. The directive allows us to change the appearance or behavior of a DOM element. An Angular offers lots of built-in directives, which we had learned in the previous article. We can create our own custom directive to have a feature that is specific to our application needs which is not supported by the built-in directive.
In this article, we will learn why we need to use angular @hostBinding and @hostListener decorator and demonstrate an example of each to manipulate DOM element using angular custom directive.
Why we need angular hostbinding and angular hostlistener ?
We have already learned that the Angular directive allows us to manipulate or change the appearance of the DOM element. That means we need a way to access the DOM element that the directive is being applied to, as well as ways to modify the DOM element. Angular provides a different way to access the DOM element as follows.
- Angular ElementRef class to direct access DOM element for manipulation.
- Angular renderer2 class allows manipulation of DOM elements without touching DOM directly.
- Use of Angular hostbinding and Angular hostlistener decorator without injecting in our custom directive.
By using ElementRef to manipulate the DOM element involved risk of XSS attack. The first reason for using both angular hostbinding and host listener decorator allows us to access and manipulate the DOM element.
If angular custom directive relies heavily on browser DOM API for DOM element manipulation then it works perfectly in the browser but angular can run on different environments, as result it may have issues with the non-browser environment. Angular provides us with angular hostbinding and angular hostlistener decorator to solve the above issue.
What is the use of @HostBinding and @HostListener in angular. ?
We can use @HostBinding, @HostListerner decorator, renderer2, and ElementRef to communicate and manipulate the appearance or behavior of the host element by the angular custom directive. It is not recommended to manipulate the DOM directly with ElementRef class, because of security reasons. We can also use the @HostBinding directive to bind a DOM property of the element to an instance variable in your Angular directive. Then we can update the value of the variable, and the DOM property will automatically be updated to match.
The @HostBinding and @HostListener are two decorators in Angular that can be really useful in custom directives. These two decorators are used to access the properties and events of host elements in the directive. Bindings on the host element are defined using two decorators, @HostBinding and @HostListener, both of which are defined in the @angular/core module.
Angular @HostBinding: allows directives to communicate with their host element by setting the properties of the host element. The @HostBinding decorator binds a DOM property of the element to an instance variable in our custom Angular directive. When we update the value of the variable, the DOM property will automatically be updated to match. Let’s say you want to change the style properties like the background color of the host element.
Angular @HostListener: allows interaction with the events on the host element. The @HostListener decorator allows a directive to listen to events on its host element. We can do this by decorating a function on the component with the @HostListener() decoration. The directive can listen to events with the help of the HostListener decorator. Officially an Angular definition of @HostListner “Decorator that declares a DOM event to listen for, and provides a handler method to run when that event occurs”
Example of Angular hostbinding and angular hostlistener decorator.
Here, we are using the Angular @HostBinding() decorator to access the property on the host element to set/remove its background color by listening to the mouseover and mouseout event on the host by @HostListener.
Let’s first create an Angular project and create a custom directive hover to manipulate the DOM element appearance.
ng new custDirectiveApp
ng generate directive hoverer
The above command will create an angular project and generate a custom directive called the hoverer.directive.ts file. We need to declare our custom directive in the module where we want to use it. Angular CLI will automatically add and declare the hoverer directive class name in app.module.ts when we generate a custom directive. Here is a screenshot of our example.
import { Directive, Input, HostBinding, HostListener } from '@angular/core';
@Directive({
selector: '[hoverer]',
})
export class HovererDirective {
@HostBinding('style.background') backgroundColor: string;
@HostListener('mouseover') onMouseOver() {
this.backgroundColor = 'red';
}
@HostListener('mouseout') onMouseOut() {
this.backgroundColor = 'none';
}
}
In our custom directive, we have two listener methods on the host element.
1. mouseover: event method is called when the mouse hovers on our H1 element. Based on hover we change the background color to red and you can change any style based on your requirement.
2. mouseout: event method is called when the mouse moves away from our h1 element and based on the event we remove the background color.
Edit app.component.html to add our custom hoverer directive as
<div class="container">
<h1 hoverer>Hover over me</h1>
</div>
Following are some of the examples where we use HostBinding to set properties like
@HostBinding(‘style.height’) height:string;
@HostBinding(‘style.color’) color: string;
@HostBinding(‘style.border-color’) borderColor: string;
@HostBinding(‘attr.role’) role = ‘button’;
@HostBinding(‘class.pressed’) isPressed: boolean;
Angular hostlistener to dynamic add and remove class
We have another example on angular hostlistener to dynamic add or remove CSS class on DOM element. We have a @HostListener decorator that will listen to the click event on the host element, in our case, it is a button. When a user clicks on the button we will use renderer2 to retrieve the next sibling element. We will use renderer2 to add/remove the show class on a sibling element to control the hide/show sibling element. Check the complete example in our article on angular hostlistener to add or remove the CSS class.
Example of Angular hostlistener on Input text element
Now let’s apply the angular hostlistener decorator to a text input element. When a user enters a decimal number with more than two fraction numbers we are rounded up and the user can’t enter more than two fraction numbers. Here is a screenshot of hostlistener on text input.
Let generate our custom decorator called maxTwoDecimal using angular cli.
ng g directive maxTwoDecimal
Let’s edit our custom directive of the input hostlistener file called max-two-decimal.directive.ts
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appMaxTwoDecimal]'
})
export class MaxTwoDecimalDirective {
@Input() appMaxTwoDecimal: number;
constructor(private elRef: ElementRef) { }
@HostListener('input') onInput(event) {
const num = this.elRef.nativeElement.value;
if (num && (num - Math.floor(num) !== 0)) {
this.elRef.nativeElement.value = parseFloat(num).toFixed(2)
}
}
}
Here we have hostlistener input event, where we are checking if the number has a fraction, if so then we return only two fraction number even user enter more than two.
Now let applied our custom directive input angular hostlistener on a component template, here we are applying in the app.component.html template, and let’s edit it.
<h2>Enter a number with decimal</h2>
<input type="number" [appMaxTwoDecimal]="3">
<router-outlet></router-outlet>
Applying angular hostlistener on document element
In our previous example, we have applied angular hostlistener input on text input and we can apply hostListener to any element. In this example, we applied the angular hostlister keyboard down event on the document element. When the user presses keyboard character g then we are setting document color to green, if character b is pressed then set background to blue otherwise to yellow. Here is a screenshot of our example.
Let edit our app.component.ts file to add our logic for angular listener key down event on a document to change the background color.
import { Component, ElementRef, HostListener, Renderer2 } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor(
private elRef: ElementRef,
private renderer: Renderer2) { }
@HostListener('document:keydown', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
if (event.key == 'g') {
this.renderer.setStyle(this.elRef.nativeElement.ownerDocument.body,'backgroundColor', 'green');
} else if (event.key == 'b') {
this.renderer.setStyle(this.elRef.nativeElement.ownerDocument.body,'backgroundColor', 'blue');
} else {
this.renderer.setStyle(this.elRef.nativeElement.ownerDocument.body,'backgroundColor', 'yellow');
}
}
}
We have to inject angular elementRef and renderer2 in our component constructor. When the user presses the key character g we are setting the document background color green, if b then to the blue background, and otherwise to yellow background color to document.
Conclusion
In this article, we have explored details on Angular hostbinding and angular hostlistener. We have learned why we need these two decorators to manipulate the DOM element. We demonstrated an example of both decorators. I hope that this article was able to get you up and running with angular hostbinding and angular hostlistener.