I am trying to get values that I type using an on-screen keyboard into a custom HTML element input field to display.
However I am currently getting empty strings. If I use a normal input field then it works fine.
Here is a snippet of my code and a stackblitz example which will have detailed code.
HTML
<form-input
appOskInput
[formStatus]="formStatus"
[parentFormGroup]="setupForm"
[data]="{
formControlName: 'email',
name: 'email'
}">
</form-input>
<app-keyboard></app-keyboard>
Keyboard directive
private onKey(key: string) {
let element = this.el.nativeElement;
let inputEl = element.querySelector('input');
let start = inputEl.selectionStart;
let end = inputEl.selectionEnd;
this.measure.textContent = inputEl.value.substr(0, start) key;
inputEl.value = inputEl.value.substr(0, start) key inputEl.value.substr(end);
if (this.control)
this.control.control.setValue(inputEl.value)
inputEl.focus();
inputEl.selectionStart = inputEl.selectionEnd = start 1;
this.updateScrollPosition();
}
Here is the stackblitz https://stackblitz.com/edit/onscreen-keyboard-hlmkvv?file=src/app/app.component.ts
You will see that the values are displaying when inputted from a normal input field but I can't get the same to happen when using my custom HTML element input field. I have commented out the custom HTML input field in the code on the HTML page. Can anyone help please?
CodePudding user response:
Issue:
You are adding the directive to a custom element & listening the events on the custom element instead of actual input field. Since, you have @HostListener
for focus
& blur
events inside the directive, these events don't fire in case of custom component. Because your custom component doesn't fire focus
and blur
events. (If we want any custom element to be focusable, we add tabindex=0
to make it focusable in the natural tabbing order of the webpage).
Why it work on native input elements?
Because native input elements emit focus
& blur
events. Therefore, you are able to see the virtual keyboard when you apply the directive to native input
.
Solution:
You need to add event listeners to the native input
field inside your custom component. Since, the directive is generic, you can use querySelector()
on the nativeElement inside OskInputDirective
to access the particular input field.
In OskInputDirective
, add focus
& blur
listeners in ngAfterViewInit
:
ngAfterViewInit(){
this.inputEl=this.el.nativeElement.querySelector('input');
this.inputEl?.addEventListener('focus',this.onFocus.bind(this));
this.inputEl?.addEventListener('blur',this.onBlur.bind(this));
}
Now, you can use this.inputEl
to refer to the input element inside your onKey()
method.
Note 1: Here, we are binding the callbacks with the context of OskInputDirective
. Else, this
will refer to the DOM event.
Note 2: Since we are manually subscribing to the DOM event, Angular won't be able to detect changes & update your FormControl
value. You need to emit an event when you change the input
value from virtual keyboard.
In onKey()
, call event emitter at the end. Now, listen to this event in the parent & update the corresponding form control value:
this.inputChanged.emit(element.value);
this.updateScrollPosition();
Here is the forked stackblitz with a custom input element created for reference. https://stackblitz.com/edit/onscreen-keyboard-na5kqr?file=src/app/app.component.ts