Форматирование и проверка в рамках одной директивы - PullRequest
0 голосов
/ 05 мая 2020

Я пытаюсь создать директиву для работы с моими формами, которые имеют дело с длительностями. Я хочу, чтобы форма отображалась с текстовым полем в формате 1:24, но со значением общего количества минут - в данном случае 144 (это упростит добавление большого количества раз позже!).

Вот мой текущий код:

@Directive({
...
)
export class DurationFormatDirective implements ControlValueAccessor {
  @HostBinding('value') inputValue;

  mins: number;
  onChange;
  onTouched;

  constructor() {}

  @HostListener('blur', ['$event.target.value'])
  onBlur(value: string) {
    let hrs: number, mins: number;

    if (value === '' || value === '0') {
      hrs = 0;
      mins = 0;
    } else {
      if (value.indexOf(':') === -1) { // there is no colon
        if (value.length <= 2) {
          hrs = 0;
          mins = +value;
        } else {
          hrs = +value.substring(0, value.length - 2);
          mins = +value.substring(value.length - 2);
        }
      } else { // There is a colon
        const arr = value.split(':');
        hrs = +arr[0];
        mins = +arr[1];
      }
    }

    this.mins = hrs * 60 + mins;
    this.inputValue = `${hrs}:${mins < 10 ? '0' : ''}${mins}`;
    this.onChange(this.mins);
    this.onTouched();
  }

  writeValue(val) {
    this.mins = val;

    const hrs = Math.floor(val / 60);
    const mins = val % 60;

    this.inputValue = `${hrs}:${mins < 10 ? '0' : ''}${mins}`;
  }

  registerOnChange(fn) {
    this.onChange = fn;
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }
}

Обычно это работает хорошо, но если пользователь вводит, например, 2: zw - он ломается, потому что zw не является числом. Если введено недопустимое значение (IE Not 0-9 или :), оно должно объявить поле недопустимым и не пытаться отформатировать его или обновить значение. Могу ли я сделать так, чтобы эта директива одновременно изменила действительное свойство. Если это имеет значение, я использую реактивные формы.

Спасибо

1 Ответ

0 голосов
/ 06 мая 2020

Таким образом, я решил это по-другому.

Я добавил тест RegExp для поиска букв и оператор if для поиска минут> 60. В любом случае установлено значение NaN.

Затем я создал очень простой валидатор для проверки NaN в родительской форме.

Это также позволяет мне выполнить еще одну проверку позже, где я проверяю, что введенная продолжительность не превышает общую продолжительность из другого поля.

Полный код для директивы:

@Directive({
  selector: '[appTimeFormat]',
})
export class TimeFormatDirective implements ControlValueAccessor {
  @HostBinding('value') inputValue;

  onChange;
  onTouched;

  private regex = /^\d{1,2}:?\d{0,2}$/;

  constructor() {}

  @HostListener('blur', ['$event.target.value'])
  onBlur(value: string) {
    this.onTouched();

    if (!this.regex.test(value)) {
      this.onChange(NaN);
      return;
    }

    let hrs: number, mins: number;

    if (value === '' || value === '0') {
      hrs = 0;
      mins = 0;
    } else {
      if (value.indexOf(':') === -1) {
        // There is no colon
        if (value.length <= 2) {
          hrs = 0;
          mins = +value;
        } else {
          hrs = +value.substring(0, value.length - 2);
          mins = +value.substring(value.length - 2);
        }
      } else {
        // There is a colon
        const arr = value.split(':');
        hrs = +arr[0];
        mins = +arr[1];
      }
    }

    this.inputValue = `${hrs}:${mins < 10 ? '0' : ''}${mins}`;

    if (mins > 60) {
      this.onChange(NaN);
      return;
    }

    this.onChange(hrs * 60 + mins);
  }

  writeValue(val) {
    if (val) {
      const hrs = Math.floor(val / 60);
      const mins = val % 60;

      this.inputValue = `${hrs}:${mins < 10 ? '0' : ''}${mins}`;
    } else {
      this.inputValue = '';
    }
  }

  registerOnChange(fn) {
    this.onChange = fn;
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }
}

Валидатор:

  nanValidator(control: FormControl) {
    if (isNaN(control.value)) {
      return { invalidNumber: true };
    }
    return null;
  }
...