Angular 11 custom directive makes caret jump to the end of text in input field

  angular, angular-directive, javascript, typescript

I have this custom Angular directive which converts Arabic and Persian numerals to English numerals as the user is typing.

In Safari though, the caret jumps to the end of the input text and won’t let you manually move it back. If the user wants to change something they’ve written, then they have to delete the entire thing and start over.

Here’s my directive:

import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';

@Directive({
  selector: '[convertToEnglishNumeral]',
})
export class ConvertToEnglishNumeralDirective {
  constructor(private elRef: ElementRef, private renderer: Renderer2) {}

  @HostListener('keyup', ['$event'])
  @HostListener('input', ['$event'])
  @HostListener('change', ['$event'])
  @HostListener('focusout', ['$event'])
  @HostListener('mouseleave', ['$event'])
  onInputChange(event) {
    const inputVal = this.elRef.nativeElement.value;
    this.renderer.setProperty(
      this.elRef.nativeElement,
      'value',
      convertToEnglishNumeral(inputVal)
    );
  }

  convertToEnglishNumeral(text: any): string {
    return text.toString().replace(/[u0660-u0669u06f0-u06f9]/g, (c) => {
      // tslint:disable-next-line: no-bitwise
      return c.charCodeAt(0) & 0xf;
    });
  }
}

I tried using setSelectionRange to overcome this problem, like so:

  @HostListener('keyup', ['$event'])
  @HostListener('input', ['$event'])
  @HostListener('change', ['$event'])
  @HostListener('focusout', ['$event'])
  @HostListener('mouseleave', ['$event'])
  onInputChange(event) {
    const inputVal = this.elRef.nativeElement.value;
    let start = this.elRef.nativeElement.selectionStart;
    let end = this.elRef.nativeElement.selectionEnd;
    this.renderer.setProperty(
      this.elRef.nativeElement,
      'value',
      convertToEnglishNumeral(inputVal)
    );

    this.elRef.nativeElement.setSelectionRange(start, end);
  }

but this only works if the input type is text, search, URL, tel and password. And I have all kinds of inputs like number and email that are using this directive.

I’m looking for a workaround or a solution that doesn’t include changing all my input types to text.

Source: Ask Javascript Questions

LEAVE A COMMENT