动态嵌套反应形式:ExpressionChangedAfterItHasBeenCheckedError

Eri*_*and 15 javascript forms angular

我的反应形式是深层的三个组成部分.父组件创建一个没有任何字段的新表单,并将其传递给子组件.

首先,外形有效.稍后,子组件会添加带有验证器的新表单元素(失败),使外部表单无效.

我在控制台中收到ExpressionChangedAfterItHasBeenCheckedError错误.我想解决这个错误.

不知何故,只有当我添加第三级嵌套时才会发生这种情况.同样的方法似乎适用于两层嵌套.

Plunker: https ://plnkr.co/edit/GymI5CqSACFEvhhz55l1 ? p = preview

父组件

@Component({
  selector: 'app-root',
  template: `
    myForm.valid: <b>{{myForm.valid}}</b>
    <form>
      <app-subform [myForm]="myForm"></app-subform>
    </form>
  `
})
export class AppComponent implements OnInit {
  ...

  ngOnInit() {
    this.myForm = this.formBuilder.group({});
  }
}
Run Code Online (Sandbox Code Playgroud)

子组件

@Component({
  selector: 'app-subform',
  template: `
    <app-address-form *ngFor="let addressData of addressesData;"
      [addressesForm]="addressesForm">
    </app-address-form>
  `
})
export class SubformComponent implements OnInit {
  ...

  addressesData = [...];

  constructor() { }

  ngOnInit() {
    this.addressesForm = new FormArray([]);
    this.myForm.addControl('addresses', this.addressesForm);
  }
Run Code Online (Sandbox Code Playgroud)

儿童组件

@Component({
  selector: 'app-address-form',
  template: `
    <input [formControl]="addressForm.controls.addressLine1">
    <input [formControl]="addressForm.controls.city">
  `
})
export class AddressFormComponent implements OnInit {
  ...

  ngOnInit() {
    this.addressForm = this.formBuilder.group({
      addressLine1: [
        this.addressData.addressLine1,
        [ Validators.required ]
      ],
      city: [
        this.addressData.city
      ]
    });

    this.addressesForm.push(this.addressForm);
  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Max*_*kyi 21

要了解问题,您需要阅读有关ExpressionChangedAfterItHasBeenCheckedError错误文章的所有内容.

对于您的特定情况,问题是您正在创建表单AppComponent{{myForm.valid}}在DOM中使用插值.这意味着角将运行创建和运行updateRenderer功能AppComponent的更新DOM.然后使用ngOnInit子组件的生命周期钩子将具有控件的子组添加到此表单:

export class AddressFormComponent implements OnInit {
  @Input() addressesForm;
  @Input() addressData;

  ngOnInit() {
    this.addressForm = this.formBuilder.group({
      addressLine1: [
        this.addressData.addressLine1,
        [ Validators.required ]   <-----------
      ]

    this.addressesForm.push(this.addressForm); <--------
Run Code Online (Sandbox Code Playgroud)

控件变为无效,因为您没有提供初始值并且您指定了所需的验证器.因此整个表单变得无效,表达式的{{myForm.valid}}计算结果为false.但是当Angular运行变更检测时,AppComponent它被评估为true.这就是错误所说的.

一个可能的解决方法是在开始时将表单标记为无效,因为您计划添加所需的验证器,但似乎Angular不提供此类方法.您最好的选择可能是异步添加控件.事实上,这就是Angular在源中所做的事情:

const resolvedPromise = Promise.resolve(null);

export class NgForm extends ControlContainer implements Form {
  ...

  addControl(dir: NgModel): void {
    // adds controls asynchronously using Promise
    resolvedPromise.then(() => {
      const container = this._findContainer(dir.path);
      dir._control = <FormControl>container.registerControl(dir.name, dir.control);
      setUpControl(dir.control, dir);
      dir.control.updateValueAndValidity({emitEvent: false});
    });
  }
Run Code Online (Sandbox Code Playgroud)

所以对你来说这将是:

const resolvedPromise = Promise.resolve(null);

@Component({
   ...
export class AddressFormComponent implements OnInit {
  @Input() addressesForm;
  @Input() addressData;

  addressForm;

  ngOnInit() {
    this.addressForm = this.formBuilder.group({
      addressLine1: [
        this.addressData.addressLine1,
        [ Validators.required ]
      ],
      city: [
        this.addressData.city
      ]
    });

    resolvedPromise.then(() => {
       this.addressesForm.push(this.addressForm); <-------
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

或者在AppComponent保持表单状态中使用一些变量并在模板中使用它:

{{formIsValid}}

export class AppComponent implements OnInit {
  myForm: FormGroup;
  formIsValid = false;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.formBuilder.group({});
    this.myForm.statusChanges((status)=>{
       formIsValid = status;
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 一个框架从根本上存在问题,它不能让开发人员在没有看到所有这些异常、阅读所有这些文章并跳过所有这些障碍的情况下完成如此基本的事情。 (2认同)