appSearchbox
and its usage in HTML.input
is 2-way binded using ruleSearchText
.ruleSearchText
variable value from the directive, so that the change gets triggered back again in ngOnChanges
clearInputField
clears the value, but it doesnt trigger ngOnchanges
and also any other events that listens for the value change in the underlying component.<input
#search
name="search"
type="text"
class="form-control underlined"
placeholder="Search Rule Name"
[(ngModel)]="ruleSearchText"
[appSearchbox]="ruleSearchText"
/>
import {
Directive,
ElementRef,
Input,
OnChanges,
OnDestroy,
Renderer2
} from '@angular/core';
/**
* Directive to add CANCEL button functionality for input boxes.
* Clicking cancel button will clear input box value.
*
* @export
* @class SearchboxDirective
* @implements {OnChanges}
* @implements {OnDestroy}
*/
@Directive({
selector: '[appSearchbox]',
})
export class SearchboxDirective implements OnChanges, OnDestroy {
/**
* Use inputs variable that holds value to bind with attribute.
*
* @example <input name="search" type="text" [(ngModel)]="searchTextVar" [appSearchbox]="searchTextVar"/>
*
* @memberof SearchboxDirective
*/
@Input() public appSearchbox;
public cancelContainer;
public cancelStyle;
public unlistener;
/**
* Creates an instance of SearchboxDirective.
* @constructor
* @param {ElementRef} el
* @param {Renderer2} renderer
* @memberof SearchboxDirective
*/
public constructor(private el: ElementRef, private renderer: Renderer2) {
this.cancelStyle = {
top: '50%',
right: '0.5rem',
transform: 'translateY(-50%)',
cursor: 'pointer',
};
}
/**
* Triggers when to ADD/REMOVE cancel icon to inputbox.
*
* @param {*} changes
* @memberof SearchboxDirective
*/
public ngOnChanges(changes) {
if (
changes.appSearchbox.currentValue === '' ||
changes.appSearchbox.currentValue === undefined
) {
this.toggleCancelIcon(false);
} else if (changes.appSearchbox.currentValue !== '') {
this.toggleCancelIcon(true);
}
}
/**
* Removes/cleans CLICK event listener of cancel icon.
*
* @memberof SearchboxDirective
*/
public ngOnDestroy() {
if (this.unlistener) {
this.unlistener();
}
}
/**
* Show / Hide cancel icon.
*
* @param {true|false} state
* @memberof SearchboxDirective
*/
private toggleCancelIcon(state) {
if (state === true) {
const cancelBtn = this.renderer
.parentNode(this.el.nativeElement)
.querySelector('#inputCancelBtn');
if (!cancelBtn) {
this.cancelStyle['height'] = `${this.el.nativeElement.clientHeight}px`;
this.renderer.setStyle(
this.el.nativeElement,
'padding-right',
'2.5rem'
);
this.cancelContainer = this.renderer.createElement('div');
this.renderer.setAttribute(
this.cancelContainer,
'id',
'inputCancelBtn'
);
this.renderer.setAttribute(
this.cancelContainer,
'class',
'd-inline-block position-absolute'
);
this.unlistener = this.renderer.listen(
this.cancelContainer,
'click',
() => {
this.cleatInputField();
}
);
this.setRendererStyles(this.cancelContainer, this.cancelStyle);
const cancelButton = this.renderer.createElement('span');
this.renderer.setAttribute(
cancelButton,
'class',
'icon icon-close-thin'
);
this.renderer.appendChild(this.cancelContainer, cancelButton);
this.renderer.appendChild(
this.renderer.parentNode(this.el.nativeElement),
this.cancelContainer
);
}
} else if (state === false) {
const cancelBtn = this.renderer
.parentNode(this.el.nativeElement)
.querySelector('#inputCancelBtn');
if (cancelBtn) {
this.renderer.removeChild(
this.renderer.parentNode(this.el.nativeElement),
cancelBtn
);
this.renderer.setStyle(
this.el.nativeElement,
'padding-right',
'init'
);
}
}
}
/**
* Loop through styles object and set given elements styles using Renderer2 setStyle method.
*
* @param {*} element
* @param {Object} styles
* @memberof SearchboxDirective
*/
private setRendererStyles(element, styles) {
for (const [key, value] of Object.entries(styles)) {
this.renderer.setStyle(element, key, value);
}
}
private clearInputField() {
this.el.nativeElement.value = '';
this.toggleCancelIcon(false);
}
}
You can use output
in the directive to pass the 'X' event form directive to the component like this:
<input
#search
name="search"
type="text"
class="form-control underlined"
placeholder="Search Rule Name"
[(ngModel)]="ruleSearchText"
[appSearchbox]="ruleSearchText"
(clearSearch)="clearText($event)"
/>
In the directive(appSearchbox) add this method on clearing text and the output decorator:
@Output() clearSearch = new EventEmitter();
..
..
..
clear() {
this.clearSearch.emit(true);
}
In the parent component add this:
clearText(status) {
this.ruleSearchText = status ? '' : this.ruleSearchText;
}