Search code examples
angulartypescriptangular11using-directivescustom-directive

How to apply mask to a default value in Typescript


I have a mask-phone directive that works perfectly in the input when the user write a value, but I need to set a default value and I don't know how to apply the mask directive in the component method. The value is show it in the input without the mask and only if I modify that value the mask comes.

The problem I have is that in Germany has several possibilities for a telephone number, so I can not set a specific mask in the default value, for example: (49)(170)-1111111 (49)(1514)-1111111 (49)(25679)-1111111

I wrote an example, that you can see in the follow link: https://stackblitz.com/edit/angular5-phone-mask-directive-roeqfk?file=app/app.component.ts

Thanks in advance :)


Solution

  • You could provide the default value from inside the directive and set the mask in the OnInit lifecycle hook. This would additionally have the benefit that the default value is the same each time you use this directive.

    Code:

    import {Directive, ElementRef, HostListener, OnInit} from '@angular/core';
    import {NgControl} from '@angular/forms';
    @Directive({
      selector: '[formControlName][appPhoneMask]'
    })
    export class PhoneMaskDirective implements OnInit{
      defaultValue: string = '4912345678'
    
      constructor(public ngControl: NgControl, private elementRef: ElementRef) { }
    
      ngOnInit(): void {
        this.applyMask(this.defaultValue)
      }
    
      @HostListener('ngModelChange', ['$event'])
      onModelChange(event): void {
        this.onInputChange(event, false);
      }
      @HostListener('keydown.backspace', ['$event'])
      keydownBackspace(event): void {
        this.onInputChange(event.target.value, true);
      }
      onInputChange(event, backspace): void {
        let newVal = event.replace(/\D/g, '');
        if (backspace && newVal.length <= 6) {
          newVal = newVal.substring(0, newVal.length - 1);
        }
        
        this.applyMask(newVal)
      }
    
      applyMask (value): void {
        if (value.length === 0) {
          value = '';
        } else if (value.length <= 3) {
          value = value.replace(/^(\d{0,2})/, '($1)');
        } else if (value.length <= 6) {
          value = value.replace(/^(\d{0,2})(\d{0,3})/, '($1) ($2)');
        } else if (value.length <= 12) {
          value = value.replace(/^(\d{0,2})(\d{0,3})(\d{0,7})/, '($1) ($2)-$3');
        } else if (value.length <= 13) {
          value = value.replace(/^(\d{0,2})(\d{0,4})(\d{0,7})/, '($1) ($2)-$3');
        } else if (value.length <= 14) {
          value = value.replace(/^(\d{0,2})(\d{0,5})(\d{0,7})/, '($1) ($2)-$3');
        } else {
          value = value.substring(0, 14);
          value = value.replace(/^(\d{0,2})(\d{0,5})(\d{0,7})/, '($1) ($2)-$3');
        }
        this.ngControl.valueAccessor.writeValue(value);
      }
    
      /** This method allows to keep the formControl value without the mask, in order to use it in backend queries */
      @HostListener('input') onChange(): void {
        const newVal = this.elementRef.nativeElement.value.replace(/\D/g, '');
        this.ngControl.control.setValue(newVal, {
          emitEvent: false,
          emitModelToViewChange: false,
          emitViewToModelChange: false
        });
      }
    }