3

I have a problem by using a mask and a regex on an input.

This is the input:

<mat-form-field
  >
    <mat-label >HH:mm:ss:SSS</mat-label>
    <input
      matInput
      [formControlName]="duration?.id"
      [id]="duration?.id"
      [name]="duration?.id"
      placeholder="HH:mm:ss:SSS"
      appDurationMask
      type="text"
    />
    <mat-error *ngIf="!isInvalidPattern"
      >{{ duration?.label }} is required</mat-error
    >
    <mat-error *ngIf="isInvalidPattern"
      >invalid pattern must be HH:mm:ss:SSS</mat-error
    >
  </mat-form-field>

The function isInvalidPattern looks like that:

get isInvalidPattern() {
    return this.form.controls[this.data.id].errors
      ? this.form.controls[this.data.id].errors.pattern
      : false;
  }

The mask directive looks like that:

    export class DurationMaskDirective {
  constructor(public ngControl: NgControl) {}

  @HostListener('ngModelChange', ['$event'])
  onModelChange(event) {
    this.onInputChange(event, false);
  }

  @HostListener('keydown.backspace', ['$event'])
  keydownBackspace(event) {
    this.onInputChange(event.target.value, true);
  }

  onInputChange(event, backspace) {
    let newVal = event.replace(/\D/g, '');
    if (backspace && newVal.length <= 6) {
      newVal = newVal.substring(0, newVal.length - 1);
    }
    if (newVal.length === 0) {
      newVal = '';
    } else if (newVal.length <= 2) {
      newVal = newVal.replace(/^(\d{0,2})/, '$1');
    } else if (newVal.length <= 4) {
      newVal = newVal.replace(/^(\d{0,2})(\d{0,2})/, '$1:$2');
    } else if (newVal.length <= 6) {
      newVal = newVal.replace(/^(\d{0,2})(\d{0,2})(\d{0,2})/, '$1:$2:$3');
    } else if (newVal.length <= 9) {
      newVal = newVal.replace(
        /^(\d{0,2})(\d{0,2})(\d{0,2})(\d{0,3})/,
        '$1:$2:$3:$4'
      );
    } else {
      newVal = newVal.substring(0, 9);
      newVal = newVal.replace(
        /^(\d{0,2})(\d{0,2})(\d{0,2})(\d{0,3})/,
        '$1:$2:$3:$4'
      );
    }
    this.ngControl.valueAccessor.writeValue(newVal);
    this.ngControl.valueAccessor.writeValue(newVal);
  }

The problem is pretty simple, when i wrote something in the input that doesn't fit the pattern, even if nothing is visible, the invalidpattern is set to true.

If I wrote one number then delete it, the invalidpattern is set to true. If I wrote well my pattern then add 1 number or letter or anything, even if the only thing visible is the good pattern, invalidpattern is set to true. When I debug I see that even if I delete (by using backspace) it still keep in memory the last number even if nothing is visible for the user.

For example if in the input I wrote 1 then use backspace, the user see nothing in the input but the value of this.form.controls[this.metadata.id].value is 1.

If I write 11:11:11:111 then add a 1 at the end, even if the input show 11:11:11:111 the value of this.form.controls[this.metadata.id].value is 11:11:11:1111.

What can I do to resolve this problem?

Edit

Editor stackblitz

Application url

halfer
  • 19,824
  • 17
  • 99
  • 186
user3659739
  • 434
  • 6
  • 19

0 Answers0