Условный валидатор Угловой — Проверьте другие значения управления формой и проверьте с помощью шаблона регулярных выражений

#angular #angular-reactive-forms

Вопрос:

Я работал над условным валидатором, который, по сути, должен проверять значения в 3 разных полях.

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

Если одно из полей имеет значение, форма является допустимой.

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

Я пробовал использовать условный валидатор…

  conditionalValidator(predicate: () => boolean, validator: ValidatorFn): ValidatorFn {
    return ((formControl: AbstractControl) => {
      if (!formControl.parent) {
        return null;
      }
      if (predicate()) {
        return validator(formControl);
      }
      return null;
    })
  }

 

Но моя проблема в том, что это по-прежнему делает обязательными все 3 поля, даже если еще одно имеет значение, мне нужно учитывать это в conditionalvalidator, просто я не уверен, как это сделать.

Это элементы управления формами, с помощью которых я проверяю…

       'DaytimeNumber': new FormControl('', [Validators.required, this.conditionalValidator(() => !this.CustomerForm.get('MobileNumber')!.value amp;amp; !this.CustomerForm.get('EveningNumber')!.value, Validators.pattern(this.landlineRegex))]),
      'MobileNumber': new FormControl('', [Validators.required, this.conditionalValidator(() => !this.CustomerForm.get('DaytimeNumber')!.value amp;amp; !this.CustomerForm.get('EveningNumber')!.value, Validators.pattern(this.mobileRegex))]),
      'EveningNumber': new FormControl('', [Validators.required, this.conditionalValidator(() => !this.CustomerForm.get('DaytimeNumber')!.value amp;amp; !this.CustomerForm.get('MobileNumber')!.value, Validators.pattern(this.landlineRegex))]),
 

Любые предложения о наилучшем подходе к этому или некоторые полезные ресурсы, на которые я могу сослаться, будут оценены с благодарностью.

Ответ №1:

Если я правильно понимаю, вы пытаетесь применить две отдельные проверки: первая-это проверка регулярных выражений, которая должна применяться к каждому отдельному элементу управления, другая-проверка на уровне группы, которая проверяет, имеет ли значение один из элементов управления. Разделение этих двух задач должно помочь упростить проблему (и код). Валидатор «oneOfPhoneFields» может выглядеть примерно так:

 function validateOneOfPhoneFields(form: FormGroup) {
  const daytime = form.get('dayTimeNumber').value
  const mobile = form.get('mobileNumber').value
  const evening = form.get('eveningNumber').value

  return daytime || mobile || evening
    ? null
    : { oneOfPhoneFieldsRequired: true }
} 
 

Он может быть применен ко всей форме или вложенной группе форм.

Ответ №2:

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

Вы можете удалить необходимый валидатор в элементах управления, так как хотите контролировать required аспект в перекрестном валидаторе (требуется только один, а не все). Оставьте только Validators.pattern валидатор для ваших элементов управления и добавьте перекрестный валидатор на уровне формы.

 'DaytimeNumber': new FormControl('', [Validators.pattern(this.landlineRegex)]),
'MobileNumber': new FormControl('', [Validators.pattern(this.mobileRegex)]),
'EveningNumber': new FormControl('', [Validators.pattern(this.landlineRegex)]),
 

Тогда в вашей функции перекрестного валидатора у вас может быть что-то вроде этого:

 export const multiPhoneNumberValidator: ValidatorFn = (
  control: AbstractControl
): ValidationErrors | null => {
  const dayNumber = control.get('DaytimeNumber');
  const mobileNumber = control.get('MobileNumber');
  const eveningNumber = control.get('EveningNumber');

  const hasValidDayNumber = dayNumber?.value amp;amp; dayNumber.valid;
  const hasValidMobileNumber = mobileNumber?.value amp;amp; mobileNumber.valid;
  const hasValidEveningNumber = eveningNumber?.value amp;amp; eveningNumber.valid;

  return hasValidDayNumber || hasValidMobileNumber || hasValidEveningNumber
    ? null
    : { phoneNumberRequired: true };
};

 

Затем вы можете продолжить и применить перекрестный валидатор к своей форме (или группе вложенных форм), как в документации. В компоненте, где у вас есть экземпляр группы форм, он должен выглядеть примерно так:

 this.formGroup = new FormGroup({
  // the controls for the phone numbers
}, { validators: multiPhoneNumberValidator })
 

Комментарии:

1. Спасибо за это. Но как бы вы расширили это, чтобы также рассмотреть возможность проверки шаблона?

2. @orangejuice Я обновил ответ, чтобы лучше отразить мою идею.

3. спасибо, Октавиан, но откуда бы ты это назвал в компоненте? как мне нужно было бы называть это каждый раз, когда значение одного из этих полей меняется, нет?

4. @orangejuice Переход по ссылке в моем ответе должен сделать применение тривиальным, пожалуйста, взгляните.

5. @orangejuice, Октавиан говорит, что у вас есть проверка в каждом элементе управления формой и еще в одной группе форм: this.form: this.formGroup=new FormGroup({ DaytimeNumber:new FormControl(null,Validators.pattern(..)..}, multiPhoneNumberValidator)