Как различить несколько Validators.pattern

У меня есть вход, где пользователь должен ввести долготу. Я хочу иметь возможность отображать различные сообщения об ошибках, когда пользователь вводит NaN или же Not-Precise-Enough значение. я использую FormControl.hasError('ValidatorsName') чтобы получить ошибки с проверкой, но кажется, что я не могу дифференцировать эти шаблоны.

Шаблон:

<mat-form-field class="form-field">
    <input matInput placeholder="Logitude" [formControl]="longitude">
    <mat-error *ngIf="longitude.hasError('pattern')">
        Longitude must be <strong>a number</strong>
    </mat-error>
    <!-- I want to be able to check patter2 for example -->
    <mat-error *ngIf="longitude.hasError('pattern')"> 
        Longitude must have <strong>a minimum of 5 decimal numbers</strong>
    </mat-error>
</mat-form-field>

И мой угловой код:

this.longitude = new FormControl(this.attraction.longitude, [
    // is valid number
    Validators.pattern(new RegExp('(\d{1,3})([.|,]{,1})(\d+))','gi')),
    // is precise enough
    Validators.pattern(new RegExp('(\-{0,1})(\d{1,3})([.|,]{1})(\d{5,13})','i'))
]);

Есть ли способ дать этим шаблонам идентификатор? Я буду признателен за любую помощь.

4 ответа

Решение

К сожалению, невозможно дать Validators собственный идентификатор.

ОБНОВЛЕНИЕ 17.02.2018 21:00

Как отметил в комментариях Давид Збински, что несколько ошибок с одной и той же ошибкой (например, 'pattern') получают переопределение, я обновил свой ответ.

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

  regexValidator(regex: RegExp, error: ValidationErrors): ValidatorFn {
    return (control: AbstractControl): {[key: string]: any} => {
      if (!control.value) {
        return null;
      }
      const valid = regex.test(control.value);
      return valid ? null : error;
    };
  }

и используйте это так:

  this.longitude = new FormControl('', [
    this.regexValidator(new RegExp('^[0-9]+$'), {'number': ''}),
    this.regexValidator(new RegExp('^.{5,}$'), {'precision': ''})
  ]);
  <mat-form-field class="form-field">
    <input matInput placeholder="Logitude" [formControl]="longitude">
    <mat-error *ngIf="longitude.hasError('number')">
        Longitude must be <strong>a number</strong>
    </mat-error>
    <!-- I want to be able to check patter2 for example -->
    <mat-error *ngIf="longitude.hasError('precision')">
        Longitude must have <strong>a minimum of 5 decimal numbers</strong>
    </mat-error>
</mat-form-field>

Я также обновил демонстрацию stackblitz: https://stackblitz.com/edit/angular-dvwcj3?file=app%2Fhello.component.ts

СТАРЫЙ ОТВЕТ:

Но PatternValidators возвращаются уникальные ValidatonErrorObjects,

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

return (control: AbstractControl): ValidationErrors | null => {
  if (isEmptyInputValue(control.value)) {
    return null;  // don't validate empty values to allow optional controls
  }
  const value: string = control.value;
  return regex.test(value) ? null :
                             {'pattern': {'requiredPattern': regexStr, 'actualValue': value}};
};

Имея это в виду, вы можете легко создать два метода получения внутри component.ts файл. И они отличаются между двумя регулярными выражениями. В этом примере они просто проверяют, соответствует ли уникальная подстрока регулярному выражению. Наверняка они другие способы справиться с этим.

  get numberError() {
    if (this.longitude && this.longitude.hasError('pattern')) {
      return this.longitude.getError('pattern').requiredPattern.indexOf('(\d+)') !== -1
    }
    return false;
  }

  get preciseError() {
    if (this.longitude && this.longitude.hasError('pattern')) {
      return this.longitude.getError('pattern').requiredPattern.indexOf('(\-{0,1})') !== -1
    }
    return false;
  }

Вы можете создать вспомогательную функцию, которая может изменить имя ошибки валидатора:

      function renameError(validator: ValidatorFn, name: string): ValidatorFn {
    return (control: FormControl): ValidationErrors | null => {
        const result = validator(control);
        if (result) {
            const keys = Object.keys(result);
            if (keys.length === 1) {
                result[name] = result[keys[0]];
                delete result[keys[0]];
            } else if (keys.length > 1) {
                // Just in case validator for some reason returns multiple errors
                result[name] = {valid: false};
            }
         }
         return result;
    };
}

и используйте его так:

      this.longitude = new FormControl(this.attraction.longitude, [
    renameError(
        Validators.pattern(new RegExp('(\d{1,3})([.|,]{,1})(\d+))','gi')),
        'notANumber'
    ),
    renameError(
        Validators.pattern(new RegExp('(\-{0,1})(\d{1,3})([.|,]{1})(\d{5,13})','i')),
        'notPrecise'
    )
]);
      <mat-form-field class="form-field">
    <input matInput placeholder="Logitude" [formControl]="longitude">
    <mat-error *ngIf="longitude.hasError('notANumber')">
        Longitude must be <strong>a number</strong>
    </mat-error>
    <mat-error *ngIf="longitude.hasError('notPrecise')"> 
        Longitude must have <strong>a minimum of 5 decimal numbers</strong>
    </mat-error>
</mat-form-field>

Решение SplitterAlex не сработало для меня, пока я не изменил значение объекта ошибки с ''к true

      this.longitude = new FormControl('', [
    this.regexValidator(new RegExp('^[0-9]+$'), {'number': true}),
    this.regexValidator(new RegExp('^.{5,}$'), {'precision': true})
  ]);

Мне нужно было настроить ответ @SoMuchSpace для angular 16:

      renameError(validator: ValidatorFn, name: string): ValidationErrors | null {
    return (control: FormControl): ValidationErrors | null => {
      const result = validator(control);
      if (result) {
        const keys = Object.keys(result);
        if (keys.length === 1) {
          result[name] = result[keys[0]];
          delete result[keys[0]];
        } else if (keys.length > 1) {
          // Just in case validator for some reason returns multiple errors
          result[name] = {valid: false};
        }
      }
      return result;
    };
  }

this.longitude = new FormControl(this.attraction.longitude, [
    renameError(
        Validators.pattern(new RegExp('(\d{1,3})([.|,]{,1})(\d+))','gi')),
        'notANumber'
    ) as ValidatorFn,
    renameError(
        Validators.pattern(new RegExp('(\-{0,1})(\d{1,3})([.|,]{1})(\d{5,13})','i')),
        'notPrecise'
    ) as ValidatorFn
]);

Без этой настройки я получил эту ошибку:

       error TS2322: Type '(control: FormControl) => ValidationErrors | null' is not assignable to type 'ValidatorFn'
Другие вопросы по тегам