Угловые реактивные формы AddControl Вызывает ExpressionChangedAfterItHasBeenCheckedError при использовании PatchValue

Я хотел иметь возможность создавать реактивную форму, используя компоненты, но не настраивать ее в одном родительском компоненте. Итак, я создал начальный FormGroup и передал его компонентам, которые затем делают this.form.addControl(this.fb.group({ ... })); добавить свою группу в форму.

пример

Родительский компонент

this.form = this.fb.group({}); // Empty

public ngAfterViewInit() {
  // Throws error after trying to patchValue on the child component
  this.form.get('example').patchValue({
    field1: 'Hello World!'
  });
}

Дочерние компоненты

this.parentFormGroup.addControl(
  'childGroup', 
  this.fb.group({ 
    field1: [
      '', [Validators.required]
    ], 
    etc...
  }
);

Это работает, пока я не попробую и this.form.get('childGroup').patchValue({ ... }) после подачи запроса в ngAfterViewInit Хук жизненного цикла родительского компонента. Вместо исправления группы он выдает:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has 
changed after it was checked. Previous value: 'ng-valid: false'. Current value: 
'ng-valid: true'.

Есть ли способ, чтобы дочерние компоненты добавляли себя в FormGroupи не иметь родительской установки FormGroup элементы управления и проверки. Нам нужно повторно использовать дочерние компоненты различными способами и комбинациями в приложении, поэтому мы не хотели повторять FormGroup объявление вне дочерних компонентов, но это не похоже на работу.

1 ответ

Эта ошибка появляется, потому что, исправляя значение в ngAfterViewInit, вы меняете состояние валидности формы после того, как форма уже проверена логикой обнаружения изменений Angular.

У вас есть два варианта предотвратить это:

  • Вы настраиваете форму таким образом, чтобы иметь непосредственно правильное состояние достоверности, например, передавая начальное значение дочернему элементу и устанавливая его там.

или же

  • Вы перемещаете установку значения в другой цикл обнаружения изменений, заключая patchValue в setTimeout:

    setTimeout(() => this.form.get('childGroup').patchValue({ ... }))

Другие вопросы по тегам