In my meanderings around the world wide interweb, and now especially the angular.io style docs, I find many references to @HostBinding
and @HostListener
. It seems they are quite fundamental, but unfortunately the documentation for them at the moment is a little sketchy.
Can anyone please explain what they are, how they work and give an example of their usage?
This question is related to
angular
angular-services
@HostBinding
: This decorator binds a class property to a property of the host element.@HostListener
: This decorator binds a class method to an event of the host element.import { Component, HostListener, HostBinding } from '@angular/core';
@Component({
selector: 'app-root',
template: `<p>This is nice text<p>`,
})
export class AppComponent {
@HostBinding('style.color') color;
@HostListener('click')
onclick() {
this.color = 'blue';
}
}
In the above example the following occurs:
color
property in our AppComponent
class is bound to the style.color
property on the component. So whenever the color
property is updated so will the style.color
property of our component@Directive
:Although it can be used on component these decorators are often used in a attribute directives. When used in an @Directive
the host changes the element on which the directive is placed. For example take a look at this component template:
<p p_Dir>some paragraph</p>
Here p_Dir is a directive on the <p>
element. When @HostBinding
or @HostListener
is used within the directive class the host will now refer to the <p>
.
DECORATORS: to dynamically change the behaviour of DOM elements
@HostBinding: Dynamic binding custom logic to Host element
@HostBinding('class.active')
activeClass = false;
@HostListen: To Listen to events on Host element
@HostListener('click')
activeFunction(){
this.activeClass = !this.activeClass;
}
Host Element:
<button type='button' class="btn btn-primary btn-sm" appHost>Host</button>
Another nice thing about @HostBinding
is that you can combine it with @Input
if your binding relies directly on an input, eg:
@HostBinding('class.fixed-thing')
@Input()
fixed: boolean;
// begginers
@Component({
selector: 'custom-comp',
template: ` <div class="my-class" (click)="onClick()">CLICK ME</div> `,
})
export class CustomComp {
onClick = () => console.log('click event');
}
// pros
@Component({
selector: 'custom-comp',
template: ` CLICK ME `,
})
export class CustomComp {
@HostBinding('class') class = 'my-class';
@HostListener('click') onClick = () => console.log('click event');
}
// experts
@Component({
selector: 'custom-comp',
template: ` CLICK ME `,
host: {
class: 'my-class',
'(click)': 'onClick()',
},
})
export class CustomComp {}
------------------------------------------------
The 1st way will result in:
<custom-comp>
<div class="my-class" (click)="onClick()">
CLICK ME
<div>
</custom-comp>
The last 2 ways will result in:
<custom-comp class="my-class" (click)="onClick()">
CLICK ME
</custom-comp>
@Hostlistnening deals basically with the host element say (a button) listening to an action by a user and performing a certain function say alert("Ahoy!") while @Hostbinding is the other way round. Here we listen to the changes that occurred on that button internally (Say when it was clicked what happened to the class) and we use that change to do something else, say emit a particular color.
Think of the scenario that you would like to make a favorite icon on a component, now you know that you would have to know whether the item has been Favorited with its class changed, we need a way to determine this. That is exactly where @Hostbinding comes in.
And where there is the need to know what action actually was performed by the user that is where @Hostlistening comes in
Here is a basic hover example.
Component's template property:
Template
<!-- attention, we have the c_highlight class -->
<!-- c_highlight is the selector property value of the directive -->
<p class="c_highlight">
Some text.
</p>
And our directive
import {Component,HostListener,Directive,HostBinding} from '@angular/core';
@Directive({
// this directive will work only if the DOM el has the c_highlight class
selector: '.c_highlight'
})
export class HostDirective {
// we could pass lots of thing to the HostBinding function.
// like class.valid or attr.required etc.
@HostBinding('style.backgroundColor') c_colorrr = "red";
@HostListener('mouseenter') c_onEnterrr() {
this.c_colorrr= "blue" ;
}
@HostListener('mouseleave') c_onLeaveee() {
this.c_colorrr = "yellow" ;
}
}
One thing that adds confusion to this subject is the idea of decorators is not made very clear, and when we consider something like...
@HostBinding('attr.something')
get something() {
return this.somethingElse;
}
It works, because it is a get
accessor. You couldn't use a function equivalent:
@HostBinding('attr.something')
something() {
return this.somethingElse;
}
Otherwise, the benefit of using @HostBinding
is it assures change detection is run when the bound value changes.
A quick tip that helps me remember what they do -
HostBinding('value') myValue;
is exactly the same as [value]="myValue"
And
HostListener('click') myClick(){ }
is exactly the same as (click)="myClick()"
HostBinding
and HostListener
are written in directives
and the other ones (...)
and [..]
are written inside templates (of components).
Source: Stackoverflow.com