Угловой - динамически добавлять/удалять валидаторы

У меня есть FormGroup как FormGroup ниже:

this.businessFormGroup: this.fb.group({
    'businessType': ['', Validators.required],
    'description': ['', Validators.compose([Validators.required, Validators.maxLength(200)])],
    'income': ['']
  })

Теперь, когда businessType is Other, я хочу удалить Validators.required validator из description. И если businessType не является Other, я хочу добавить обратно Validators.required.

Я использую приведенный ниже код для динамического добавления/удаления Validators.required. Однако он очищает существующий валидатор Validators.maxLength.

if(this.businessFormGroup.get('businessType').value !== 'Other'){
    this.businessFormGroup.get('description').validator = <any>Validators.compose([Validators.required]);               
} else {                
    this.businessFormGroup.get('description').clearValidators();               
}

this.businessFormGroup.get('description').updateValueAndValidity(); 

Мой вопрос в том, как сохранить существующие валидаторы при добавлении/удалении required валидатора.

Ответы

Ответ 1

Angular формы имеют встроенную функцию setValidators(), которая позволяет программно назначать валидаторы.

Для вашего примера вы можете сделать:

if(this.businessFormGroup.get('businessType').value !== 'Other'){
    this.businessFormGroup.controls['description'].setValidators([Validators.required, Validators.maxLength(200)]);              
} else {                
    this.businessFormGroup.controls['description'].setValidators([Validators.maxLength(200)]);               
}

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

Ответ 2

Эта работа для меня

   onAddValidationClick(){
         this.formGroup.controls["firstName"].setValidators(Validators.required);
        this.formGroup.controls["firstName"].updateValueAndValidity();
      }

onRemoveValidationClick(){
         this.formGroup.controls["firstName"].clearValidators();
        this.formGroup.controls["firstName"].updateValueAndValidity();
      }

Ответ 3

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

Рассмотрим существование descriptionIsRequired, которое будет использоваться в качестве флагов boolan.

Идеи:

  • Создайте пользовательскую функцию валидатора, которая принимает аргумент descriptionIsRequired как аргумент, и в зависимости от этого проверяет контроль над требуемой + maxLength или maxLength.
  • Привяжите настраиваемый валидатор к элементу управления описанием таким образом, чтобы при оценке действительности элемента управления учитывалось самое новое значение descriptionIsRequired.

Первый момент довольно прост в реализации:

function descriptionValidator(required: boolean): ValidatorFn {
  return (formControl: FormControl): ValidationErrors => {
    if (required) {
      return Validators.compose([Validators.required, Validators.maxLength(200)])(formControl);
    } else {
      return Validators.maxLength(200)(formControl);
    }
  }
}

Обратите внимание, что это функция с самопроверкой.

Второй момент немного сложнее, но в конце он выглядит так:

export class FooComponent {
  constructor(){
    this.form = fb.group({
      description: ['initial name', this.validator()]
    });
  }

  private get descriptionIsRequired(): boolean {
   ...
  }

  private validator(): ValidatorFn {
    return (c: FormControl): ValidationErrors => descriptionValidator(this.descriptionIsRequired)(c);
  }
}

Небольшое объяснение того, что происходит:

  • метод validator возвращает функцию
  • функция, возвращаемая validator может считаться фабричным методом: всякий раз, когда она вызывается, возвращает новую функцию, а точнее, новый экземпляр нашего descriptionValidator используя новое значение descriptionIsRequired.

Живая демонстрация в следующем стеке

Ответ 4

Может быть, это поможет:

Добавление Validators.required в набор валидаторов существующего AbstractControl:

if (c.validator !== null) {
        c.setValidators([c.validator, Validators.required])
  } else {
        c.setValidators([Validators.required])
  }

Ответ 5

Любой, кто все еще ищет ответ, может сделать это следующим образом, обработав его в ngOnInit() или в любом другом месте, которое вам нравится.

   const validators = formGroup.validator; /* or control.validator */

   const newValidator = CustomValidator.checkUserNameValidity(); 

   /* Add to existing validator */

   if(validator) {
      formGroup.setValidators([validators, newValidator])
   } else {. /* if no validators added already */
      formGroup.setValidators([newValidator]);
   }

Выполните то же самое для asyncValidator.