如何屏蔽自定义控件中的值

How to mask value in custom control

如何在输入中显示转换后的值(例如“1(234)567-890”),而没有转换后的值('1234567890')?

是否可以为 maskInputElmaskInput 设置分隔值?

我有模板:

   <input #maskInputEl class="spacer" [type]="type"
   [formControl]="maskInput"/>

和自定义组件:

export class MaskInputComponent implements ControlValueAccessor, OnInit, OnDestroy {
    @ViewChild('maskInputEl') public maskInputEl: ElementRef;

    @Input() public mask: any[];

    public maskInput = new FormControl();

    private _oldValue: string = '';

    public ngOnInit(): void {
        this.maskInput.valueChanges
            .subscribe((value: string) => {
                    let valid = this.isValidValueByMask(value, this.mask);
                    if (valid) {
                        this._oldValue = value;
                    } else {
                        value = this._oldValue;
                    }

                    this._onChangeCallback(value);
                    this.onChange.emit(value);

                    this.maskInputEl.nativeElement.value = value; 
                },
                (err) => console.warn(err)
            );
    }

    public toggleActive(value) {
        //
    }

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

    public registerOnTouched(fn: any): void {
        this._onTouchedCallback = fn;
    }

    public _onChangeCallback: Function = (_: any) => {
        //
    }

    public _onTouchedCallback: Function = (_: any) => {
        //
    }

    public makeActive() {
        this.maskInputEl.nativeElement.focus();
    }

    public writeValue(value: string): void {
        this.maskInput.setValue(value);
    }

    public ngOnDestroy(): void {
        //
    }

    private isValidValueByMask(value: string, mask: RegExp[]): boolean {
        //
    }
}

是的,这是可能的。我为我自己的项目做了类似的事情,我想创建一个 MoneyFieldComponent 返回以美分为单位的值,但允许用户以美元和美分输入他们的货币价值。

基本概念是您的组件必须存储原始值,但是,您在文本字段中显示格式化值。此外,当用户与您的文本字段交互时,您会使用原始值更新组件的 'inner value'。

请注意,您不应使用 ngModel 来更新您的文本字段 - ngModel 具有一些在这些情况下会造成严重破坏的异步行为 - 您可以使用原始 javascript(或者在我的情况下,我使用了 FormControl).

样本:

@Component({
  selector: 'ec-money-field',
  template: `
      <md-input-container *ngIf="editMode">
          <input #input mdInput class="value" type="text"
                 (input)="updateInnerValue(input.value)"
                 (blur)="formatTextValue()"
                 [formControl]="control" />
      </md-input-container>
  `,
  providers: [
    {provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => MoneyFieldComponent)},
  ]
})
export class MoneyFieldComponent implements OnInit, ControlValueAccessor {

  private valueInCents = 0;
  control = new FormControl(0);

  private onChange: Function = (_: any) => {};
  private onTouch: Function = (_: any) => {};

  constructor() { }

  @Input()
  get value(): number {
    return this.valueInCents;
  };

  // if you update the component by using the value property,
  // propagate that change to the text field    
  set value(newValueInCents: number) {
    this.valueInCents = newValueInCents;
    this.control.setValue(centsToDollars(newValueInCents));
  }

  ngOnInit() {
  }

  // convert the masked value - i.e. what the user types
  // into the actual numerical value that will be stored
  // You'll have to provide your own conversion function 
  // to convert the user typing 1(855) 555 1234 to 1865551234
  updateInnerValue(dollarValueString: string) {
    this.valueInCents = dollarsToCents(dollarValueString);
    this.onChange(this.valueInCents);
  }

  formatTextValue() {
    this.value = this.value;
  }

  writeValue(newValue: number): void {
    this.value = newValue;
  }

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

  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }
}

请注意,以上是该组件的简化版本。 The full version can be found on Github.