all files / src/ angular2TextMask.ts

50.94% Statements 27/53
0% Branches 0/20
21.43% Functions 3/14
45.24% Lines 19/42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                                                                                                                                                                                        
import { Directive, ElementRef, forwardRef, Input, Inject, NgModule, OnChanges, Provider, Renderer, SimpleChanges } from '@angular/core'
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'
import { createTextMaskInputElement } from 'text-mask-core/dist/textMaskCore'
 
export const MASKEDINPUT_VALUE_ACCESSOR: Provider = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => MaskedInputDirective),
  multi: true
}
 
@Directive({
  host: {
    '(input)': 'onInput($event.target.value)',
    '(blur)': '_onTouched()'
  },
  selector: '[textMask]',
  providers: [MASKEDINPUT_VALUE_ACCESSOR]
})
export class MaskedInputDirective implements ControlValueAccessor, OnChanges {
  private textMaskInputElement: any
  private inputElement: HTMLInputElement
 
  // stores the last value for comparison
  private lastValue: any
 
  @Input('textMask')
  textMaskConfig = {
    mask: [],
    guide: true,
    placeholderChar: '_',
    pipe: undefined,
    keepCharPositions: false,
  }
 
  _onTouched = () => {}
  _onChange = (_: any) => {}
 
  constructor(@Inject(Renderer) private renderer: Renderer, @Inject(ElementRef) private element: ElementRef) {}
 
  ngOnChanges(changes: SimpleChanges) {
    this.setupMask(true)
    if (this.textMaskInputElement !== undefined) {
      this.textMaskInputElement.update(this.inputElement.value)
    }
  }
 
  writeValue(value: any) {
    this.setupMask()
 
    // set the initial value for cases where the mask is disabled
    const normalizedValue = value == null ? '' : value
    this.renderer.setElementProperty(this.inputElement, 'value', normalizedValue)
 
    if (this.textMaskInputElement !== undefined) {
      this.textMaskInputElement.update(value)
    }
  }
 
  registerOnChange(fn: (value: any) => any): void { this._onChange = fn }
 
  registerOnTouched(fn: () => any): void { this._onTouched = fn }
 
  setDisabledState(isDisabled: boolean) {
    this.renderer.setElementProperty(this.element.nativeElement, 'disabled', isDisabled)
  }
  
  onInput(value) {
    this.setupMask()
 
    if (this.textMaskInputElement !== undefined) {
      this.textMaskInputElement.update(value)
      
      // get the updated value
      value = this.inputElement.value
 
      // check against the last value to prevent firing ngModelChange despite no changes
      if (this.lastValue !== value) {
        this.lastValue = value
        this._onChange(value)
      }
    }
  }
 
  private setupMask(create = false) {
    if (!this.inputElement) {
      if (this.element.nativeElement.tagName === 'INPUT') {
        // `textMask` directive is used directly on an input element
        this.inputElement = this.element.nativeElement
      } else {
        // `textMask` directive is used on an abstracted input element, `md-input-container`, etc
        this.inputElement = this.element.nativeElement.getElementsByTagName('INPUT')[0]
      }
    }
    
    if (this.inputElement && create) {
      this.textMaskInputElement = createTextMaskInputElement(
        Object.assign({inputElement: this.inputElement}, this.textMaskConfig)
      )
    }
    
  }
}
 
@NgModule({
  declarations: [MaskedInputDirective],
  exports: [MaskedInputDirective]
})
export class TextMaskModule {}
 
export { conformToMask } from 'text-mask-core/dist/textMaskCore'