Angular 6, this.formGroup.updateValueAndValidity() не работает должным образом

Я пытаюсь добавлять и удалять валидаторы в элементах управления formGroup на основе определенных условий.

Когда я обновляю валидаторы через formGroup.updateValueAndValidity() для всей формы, они не обновляются, а если я специально подаю заявку для каждого элемента управления, то есть formGroup.get('formControl').updateValueAndValidity(), он работает, но я должен писать для каждого элемента управления, что, я надеюсь, неправильный способ. Что я делаю не так?

if (data == 'x') {
    this.myForm.get('control2').setValue(null);
    this.myForm.get('control2').setValidators(Validators.nullValidator);
    this.myForm.get('control1').setValidators(Validators.required);
} else if (data == 'y') {
    this.myForm.get('control1').setValue(null);
    this.myForm.get('control1').setValidators(Validators.nullValidator);
    this.myForm.get('control2').setValidators(Validators.required);
}
this.myForm.get('control1').updateValueAndValidity();
this.myForm.get('control2').updateValueAndValidity();

это работает, но,

this.myForm.updateValueAndValidity();

Это не работает.


person Ashutosh Singh    schedule 13.11.2019    source источник
comment
Я считаю, что, к сожалению, вам придется ориентироваться на каждый контроллер отдельно. Кроме того, вы можете написать один метод, который будет делать это за вас каждый раз, когда он вызывается, если вам нужно повторно использовать его несколько раз.   -  person mikegross    schedule 13.11.2019


Ответы (5)


updateValueAndValidity() является восходящим, поэтому, если вы вызываете этот метод над элементом управления, он будет проверять только проверки этого элемента управления и его родителей, но не их дочерних элементов.

Дополнительные сведения см. в разделе AbstractControl#. updateValueAndValidity на github, чтобы узнать, как это работает.

  updateValueAndValidity(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
    this._setInitialStatus();
    this._updateValue();

    if (this.enabled) {
      this._cancelExistingSubscription();
      (this as{errors: ValidationErrors | null}).errors = this._runValidator();
      (this as{status: string}).status = this._calculateStatus();

      if (this.status === VALID || this.status === PENDING) {
        this._runAsyncValidator(opts.emitEvent);
      }
    }

    if (opts.emitEvent !== false) {
      (this.valueChanges as EventEmitter<any>).emit(this.value);
      (this.statusChanges as EventEmitter<string>).emit(this.status);
    }

    if (this._parent && !opts.onlySelf) {
      this._parent.updateValueAndValidity(opts);
    }
  }
person Serginho    schedule 13.11.2019
comment
Какой в ​​этом смысл? Итак, если я хочу запустить проверку всей FormGroup, я должен вызывать ее только для одного элемента управления?? Что они задумали??? - person AsGoodAsItGets; 08.04.2020

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

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

Обратите внимание, что здесь написано «предок», а не «потомки». Это означает, что если вы запустили updateValueAndValidity() для control1 и control2, и они оба действительны, myForm также будет помечено как действительное.

person ShamPooSham    schedule 13.11.2019

Как сказал Сержиньо в принятом ответе, проблема в том, что метод updateValueAndValidity является восходящим, поэтому он не будет проверять дочерние элементы управления. Возможное решение для этого — написать собственный метод прототипа для класса FormGroup следующим образом:

import { FormGroup, FormControl } from '@angular/forms';

declare module '@angular/forms/forms' {
  interface FormGroup {
    validate(): void;
  }
}

FormGroup.prototype.validate = function(this: FormGroup): void {
  for (const key in this.controls) {
    const formElement = this.get(key);
    if (formElement instanceof FormControl) {
      formElement.updateValueAndValidity();
    } else if (formElement instanceof FormGroup) {
      formElement.validate();
    }
  }
};

validate — это рекурсивный метод, который вызывает updateValueAndValidity для каждого листа (FormControl) дерева (FormGroup), даже в случае вложенных групп форм.

Не забудьте импортировать свой модуль, где вам нужно использовать метод проверки:

import '../core/extensions/formGroup';
person ssnake    schedule 22.06.2020

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: это может быть плохой практикой, но она делает то, что Angular просто не позволяет мне делать. Имейте в виду, что это очень неэффективно по сравнению со способом проверки Angular. Вот как обновить всю проверку формы:

  validateForm(control: AbstractControl) {
    control['controls'].forEach(
      // make sure to pass {onlySelf: true, emitEvent: false} 
      // or it will recurse indefinitely
      control => control.updateValueAndValidity({onlySelf: true, emitEvent: false})
    );

    return null;
  }

И для моего варианта использования мне нужно было, чтобы вся действительность формы обновлялась каждый раз, когда пользователь изменяет любое поле (а не только проверку текущего поля или только полей, которые были затронуты, yadi yada):

this.form.setValidators(this.validateForm);
person Leogout    schedule 07.10.2020

Попробуй это:

const forms = [this.form1, this.form2, this.form3];

    for (let f of forms) {
      for (let key in f.controls) {
        f.controls[key].updateValueAndValidity();
      }
    }
person brett    schedule 12.03.2021