如何动态格式化angular2中的输入元素?

How can I dynamically format an input element in angular2?

我正在使用 angular2,新形式 api。

我想要一个 phone 数字输入框,它会在用户输入时自动格式化。

例如用户类型:

12345678901

当他们输入可识别的 phone 数字时,它会变为

1 (234) 567-8901

我想出了如何将指令添加到输入控件上,但我不知道如何将自己注入到输入处理管道中。

你必须创建自己的指令,以这个为例,它使用 Phone.format 进行转换,将原始数字存储在模型中,但将格式化后的数字显示给用户:

import { Directive } from '@angular/core'
import { NgControl } from '@angular/forms'
import { Phone } from '../phone'

@Directive({
  selector: '[ngModel][phone]',
  host: {
    '(ngModelChange)': 'onInputChange($event)',
    '(blur)': 'onBlur($event)'
  }
})
export class PhoneDirective {

  constructor (control: NgControl) {
    this.control = control
  }

  ngOnInit () {
    let formatted = Phone.format(this.control.model)
    setTimeout(() => this.control.valueAccessor.writeValue(formatted), 0)
  }

  onBlur () {
    let val = this.control.model
    let raw = val.replace(/\W/g, '')
    let formatted = Phone.format(raw)

    this.control.valueAccessor.writeValue(formatted)
    this.control.viewToModelUpdate(raw)
  }

  onInputChange (val) {
    let raw = val.replace(/\W/g, '')
    if (val !== raw) this.control.viewToModelUpdate(raw)
  }
}

下面的指令将在您键入时格式化值:

  1. 当用户输入值时触发 input 方法(视图 -> 模型,又名 AngularJS 中的 $parser)。它确保视图获得格式化视图(通过 render 方法),而模型获得原始数值(通过 propagateChange 方法)。
  2. 当模型更新时触发 writeValue 方法(模型 -> 视图,在 AngularJS 中又名 $formatter)。它确保视图获得格式化视图(通过 render 方法)。
  3. format 方法包含格式化视图的逻辑。我们需要一些额外的条件来确保用户不仅可以输入字符,还可以一个一个地删除它们。

要使用该指令将其注册到模块中并link将其输入到输入中,例如:

<input appFormattedNumber formControlName= .../>

(我只用反应形式测试过)

import {Directive, ElementRef, forwardRef, HostListener, Renderer2} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';

@Directive({
  selector: '[appFormattedNumber]',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => FormattedNumberDirective),
      multi: true
    }
  ]
})
export class FormattedNumberDirective implements ControlValueAccessor {
  propagateChange;

  constructor( private renderer: Renderer2, private element: ElementRef ) {}

  @HostListener('input', [ '$event.target.value' ])
  input( value ) {
    const canonical = this.removeNonNumericCharacters(value);

    const formatted = this.format(canonical);
    this.render(formatted);

    this.propagateChange(canonical);
  }
  writeValue( value: any ): void {
    const canonical = this.removeNonNumericCharacters(value.toString());
    const formatted = this.format(canonical);
    this.render(formatted);
  }

  registerOnChange( fn: any ): void {
    this.propagateChange = fn;
  }

  registerOnTouched(fn: any): void {}

  setDisabledState(isDisabled: boolean): void {}

  private removeNonNumericCharacters(value): string {
    return value.replace(/\D/g, '');
  }

  private format(value): string {
    if (value.length < 5) {
      return value;
    }

    const int = value.substring(0, 1);
    const areaCode = value.substring(1, 4);
    const ext1 = value.substring(4, 7);
    const ext2 = value.substring(7, 11);
    const ext = ext2 ? ` ${ext1}-${ext2}` : `${ext1}`;

    return `${int} (${areaCode}) ${ext}`;
  }

  private render(value) {
    const element = this.element.nativeElement;
    this.renderer.setProperty(element, 'value', value);
  }
}