Search code examples
angularuser-inputangular-directivearabicfarsi

Angular Custom Attribute Directive doesn't work right


I have written an attribute directive to convert Persian and Arabic numbers to English numbers and I'm using it on many <input> tags all throughout my forms.

Problem is, sometimes it doesn't convert the last digits to English numbers. I mean, it shows the users that it does (conversion happens realtime because of the keyup event binding) but the information that gets sent to the server is wrong.

Example:

When I use this directive on an input, when the user enters ۱۲۳۴۵۶۷۸۹ in the input field, I expect this directive to change it to 123456789 but it changes it to 12345678۹ or sometimes 123457۸۹. (missing to convert the last digits)

convert-to-english-numeral.directive.ts:

export class Convert2EnglishNumeralDirective {
  constructor(private elRef: ElementRef, private renderer: Renderer2) {}

  @HostListener('keyup') keyup() {
    const inputVal = this.elRef.nativeElement.value;
    this.renderer.setProperty(
      this.elRef.nativeElement,
      'value',
      `${convert2EnglishNumeral(inputVal)}`
    );
  }

  @HostListener('blur') blur() {
    const inputVal = this.elRef.nativeElement.value;
    this.renderer.setProperty(
      this.elRef.nativeElement,
      'value',
      `${convert2EnglishNumeral(inputVal)}`
    );
  }

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

Solution

  • Here's how I solved this issue. I'm not sure if it's best practice or not but here it goes:

    convert-to-english-numeral.directive.ts:

    export class Convert2EnglishNumeralDirective {
      constructor(private elRef: ElementRef, private renderer: Renderer2) {}
    
      @HostListener('keyup')
      onKeyup() {
        const inputVal = this.elRef.nativeElement.value;
        this.renderer.setProperty(
          this.elRef.nativeElement,
          'value',
          convert2EnglishNumeral(inputVal)
        );
      }
    
      @HostListener('input', ['$event'])
      onInputChange(event) {
        const inputVal = this.elRef.nativeElement.value;
        this.renderer.setProperty(
          this.elRef.nativeElement,
          'value',
          convert2EnglishNumeral(inputVal)
        );
      }
    
      convert2EnglishNumeral(text: any): string {
        return text.toString().replace(/[\u0660-\u0669\u06f0-\u06f9]/g, (c) => {
          // tslint:disable-next-line: no-bitwise
          return c.charCodeAt(0) & 0xf;
        });
      }
    }