Angular:如何使用指令设置输入值的格式?

时间:2019-01-16 10:44:16

标签: javascript angular typescript angular-directive

我试图创建一个自定义指令,以允许用户在文本字段中仅键入数字,并且这些数字将使用语言环境格式(千位分隔符,十进制分隔符)进行格式化

我已经能够创建使用自定义管道的指令,但是,我无法使用正确的格式设置默认值。

我制作了一个Plunker,以便您完全了解我在说什么:

https://next.plnkr.co/edit/ToxPEEooR5lvCJOm?preview

我不知道为什么,但是我无法使Plunker上的演示应用正常工作。可能是个小问题。

这是我的指令

import { Directive, HostListener, ElementRef, OnInit, Input } from '@angular/core';
import { NumberMaskPipe } from './number-mask.pipe';

@Directive({
  selector: 'input[type=text][numberMask]'
})
export class NumberMaskDirective implements OnInit {

  private el: HTMLInputElement;
  // tslint:disable-next-line:no-input-rename
  @Input('ngModel') private initialValue: any;

  constructor(
    private elementRef: ElementRef,
    private numberMaskPipe: NumberMaskPipe
  ) {
    this.el = this.elementRef.nativeElement;
  }

  public ngOnInit() {
    console.log('ngOnInit', this.initialValue); // LOG ngOnInit 1005698
    console.log(this.numberMaskPipe.transform(this.initialValue)); // LOG 1,005,698.00
    console.log('this.el', this.el); // LOG this.el <input _ng2content-c2 class="form-control...
    console.log('this.el.value', this.el.value); // this.el.value is empty on init. Why ??
    this.el.value = this.numberMaskPipe.transform(this.initialValue); // Does not change the input value. Why ??
  }

  @HostListener('focus', ['$event.target.value'])
  onFocus(value) {
    this.el.value = this.numberMaskPipe.parse(value); // opposite of transform
  }

  @HostListener('blur', ['$event.target.value'])
  onBlur(value) {
    this.el.value = this.numberMaskPipe.transform(value);
  }

  @HostListener('keydown', ['$event']) onKeyDown(event) {
    const e = < KeyboardEvent > event;
    if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 ||
      // Allow: Ctrl+A
      (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) ||
      // Allow: Ctrl+C
      (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) ||
      // Allow: Ctrl+V
      (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) ||
      // Allow: Ctrl+X
      (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) ||
      // Allow: home, end, left, right
      (e.keyCode >= 35 && e.keyCode <= 39)) {
      // let it happen, don't do anything
      return;
    }
    // Ensure that it is a number and stop the keypress
    if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
      e.preventDefault();
    }
  }
}

能否请您告诉我如何使用使用我的指令设置格式的值来初始化输入字段?

预先感谢

1 个答案:

答案 0 :(得分:0)

ngOnInit()对任何附加的指令触发时,DOM元素的数据尚未绑定,因此该值随后绑定,并且对指令ngOnInit()所做的任何更改都将丢失。我发现可以在指令中绑定数据后才能触发函数的唯一方法是实现DoCheck

所以您想做这样的事情:

export class NumberMaskDirective implements DoCheck {
private firstRun = true;

public ngDoCheck() {
    if (firstRun) {
        this.el.value = this.numberMaskPipe.transform(this.initialValue);
        firstRun = false;
    }
}

该标志的原因是每次更新数据模型时都会调用ngDoCheck。您也可以使用ngAfterContentCheckedngAfterViewChecked,但是它们与每次更新都触发ngDoCheck的问题相同,所以我只使用ngDoCheck,因为它首先会触发其中的三个。我不确定是否有更好的生命周期挂钩可以使用,它不需要标志来确保它只能运行一次,但我找不到它。