For example you have a component, which take a trasclude input element:
<au-fa-input id="password-field" icon="lock" > <input placeholder="Password" class="test-class"> </au-fa-input>
There is many ways to get ElementRef of the input, for example using Reference:
<au-fa-input id="password-field" icon="lock" > <input #input placeholder="Password" class="test-class"> </au-fa-input>
We add a #input ref, so that inside component, we can using @ContentChild and AfterContentInit lifecycle:
export class AuFaInputComponent implements AfterContentInit{ @Input() icon: string; @ContentChild('input') input: HTMLInputElement; ngAfterContentInit () { console.log("input", this.input); }
This approach works fine, but it requires us to put a element ref onto the input field.
One way to avoid putting a reference is creating a directive ref, and we can add common functionalitiy to it, such as focus and blur events:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: 'au-fa-input input'
})
export class InputRefDirective {
focus = false;
@HostListener('focus')
isFocus() {
console.log("now focus");
this.focus = true;
}
@HostListener('blur')
isBlur() {
console.log("now blur");
this.focus = false;
}
}
And we our component, we need to change @ContentChild:
@ContentChild(InputRefDirective)
input: InputRefDirective;
So for now, in html, we don't need #input any more:
<au-fa-input id="password-field" icon="lock" > <input placeholder="Password" class="test-class"> </au-fa-input>
Now, let's say if we want to add some styling base on whether input field is focused or not.
First, some css class:
// component :host(.input-focus) { border-color: #4D90FE; -webkit-box-shadow: 0 0 5px #4D90FE; box-shadow: 0 0 5px #4D90FE; }
Use the function form to apply host styles conditionally by including another selector inside parentheses after :host. So here, we check if .input-focus is present on the host element, then we apply the styling, otherwise not.
Now we only need to apply .input-focus class to the host element when input.focus is true, we can do this easily by @HostBinding:
@HostBinding('class.input-focus') get isInputFocus() { return this.input ? this.input.focus : false; }
------
component:
import {Component, Input, ContentChild, AfterContentInit, HostBinding} from '@angular/core';
import {InputRefDirective} from 'app/lib/common/input-ref.directive';
@Component({
selector: 'au-fa-input',
templateUrl: './au-fa-input.component.html',
styleUrls: ['./au-fa-input.component.css']
})
export class AuFaInputComponent implements AfterContentInit {
@Input()
icon: string;
@ContentChild(InputRefDirective)
input: InputRefDirective;
@HostBinding('class.input-focus')
get isInputFocus() {
return this.input ? this.input.focus : false;
}
ngAfterContentInit() {
if (!this.input) {
console.error('You forgot pass in the input field');
}
}
get classes() {
const cssClasses = {};
if (this.icon) {
cssClasses['fa-' + this.icon] = true;
}
return cssClasses;
}
}
Directive:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: 'au-fa-input input'
})
export class InputRefDirective {
focus = false;
@HostListener('focus')
isFocus() {
this.focus = true;
}
@HostListener('blur')
isBlur() {
this.focus = false;
}
}