Angular: Как я могу использовать директиву для форматирования входного значения? - PullRequest
0 голосов
/ 16 января 2019

Я попытался создать пользовательскую директиву, позволяющую пользователям вводить только цифры в текстовом поле, и эти числа будут отформатированы с использованием формата локали (разделители тысяч, разделитель десятичных дробей)

Мне удалось создать директиву, в которой для этого используется пользовательский канал, однако я не могу установить значение по умолчанию в правильном формате.

Я сделал Плункер, чтобы вы точно знали, о чем я говорю:

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 голосов
/ 08 мая 2019

Данные для элемента DOM еще не связаны, когда ngOnInit() запускается для любых прикрепленных директив, поэтому значение связывается впоследствии, и любые изменения, сделанные в директивах '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 вызывается каждый раз, когда обновляется модель данных. Вы также можете использовать ngAfterContentChecked или ngAfterViewChecked, но они имеют ту же проблему, что и ngDoCheck при каждом обновлении, так что я просто использую ngDoCheck, потому что он запускает в первую очередь три из этих ловушек. Я не уверен, существует ли лучший хук жизненного цикла, для которого не требуется флаг, чтобы гарантировать, что он запускается только один раз, но я не смог его найти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...