I have a directive in Angular that should read it's host element's input selectionStart, selectionEnd values. I do this in my custom directive:
@Directive({
selector: '[inputBehavior]',
})
export class InputBehaviorDirective {
public constructor(
private el: ElementRef
) {}
@HostListener('keydown', ['$event'])
onKeyDown(event: KeyboardEvent): void {
let { selectionStart, selectionEnd } = this.el.nativeElement as HTMLInputElement;
}
}
host element's template looks like this:
<div class="input-field">
<div class="container">
<input [formControl]="formElement" />
</div>
</div>
host's typescript file:
@UntilDestroy()
@Component({
selector: 'input-field',
templateUrl: './input-field.component.html',
styleUrls: ['./input-field.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputFieldComponent),
multi: true,
},
],
})
export class InputFieldComponent implements ControlValueAccessor {
public formElement = new FormControl();
public writeValue(obj: number | string | undefined): void {
this.formElement.setValue(obj?.toString());
}
public registerOnChange(fn: any): void { }
public registerOnTouched(fn: any): void {}
public setDisabledState?(isDisabled: boolean): void {}
}
i use directive like this:
<input-field
InputBehavior
formControlName="height"
>
</input-field>
but selectionStart and selectionEnd stay undefined. I want to apply the directive to the ControlValueAccessor host element as whole and not to the native html input element within host element's tempalte. So NOT like this:
<div class="input-field">
<div class="container">
<input InputBehavior
[formControl]="formElement"
/>
</div>
</div>
so my question is, how to read selectionStart and selectionEnd values of the host element by applying the directive to it?
You can "reach" the input using el.nativeElement.getElementsByTag('input')[0]
@HostListener('keydown', ['$event'])
onKeyDown(event: KeyboardEvent): void {
const inputElement=this.el.nativeElement.getElementsByTag('input')[0]
let { selectionStart, selectionEnd } = inputElement as HTMLInputElement;
console.log(selectionStart, selectionEnd)
}
Another option can be change your directive in the way
export class InputBehaviorDirective {
public inputElement!:HTMLInputElement; //<--add a variable public
public constructor(
private el: ElementRef
) {}
@HostListener('keydown', ['$event'])
onKeyDown(event: KeyboardEvent): void {
//use the variable inputElement
let { selectionStart, selectionEnd } = this.inputElement as HTMLInputElement;
console.log(selectionStart, selectionEnd)
}
}
And your InputFieldComponent like
The template
<div class="input-field">
<div class="container">
<!--Add a template reference variable-->
<input #myinput [formControl]="formElement" />
</div>
</div>
In your .ts, inject in constructor the directive and use ViewChild with a setter
@ViewChild('myinput',{static:true}) set _myInput(value:any)
{
if (this.behaviorDirective)
this.behaviorDirective.inputElement=value;
}
constructor(@Host() @Optional() private behaviorDirective:InputBehaviorDirective){
}