Angular : 将查询参数绑定到 ExpressionChangedAfterItHasBeenCheckedError 中的表单字段结果

Angular : bind query parameter to form field results in ExpressionChangedAfterItHasBeenCheckedError

我创建了一个简单的指令,它从查询参数中获取输入并修补表单输入的值。该指令工作正常,但我收到此错误 ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'null'. Current value: 'testuser@test.be'

我在 SO / Google 上搜索了解决方案并尝试了一些,比如将我的指令的 ngOnInit 逻辑放在 ngAfterContentChecked 或 ngAfterContentInit 中,但错误仍然存​​在...... 任何人都可以指出正确的方向来解决这个问题吗?

指令'bindQueryParamToInput'

import { Directive, Input } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: '[bindQueryParamToInput]'
})
export class BindQueryparamToInputDirective {
  @Input('bindQueryParamToInput') paramKey: string;

  constructor( private ngControl : NgControl) { }

  ngOnInit() {
    const queryParams = new URLSearchParams(location.search);

    if (queryParams.has(this.paramKey)) {
      this.ngControl.control.patchValue(queryParams.get(this.paramKey));
    }
  }

}

component.html 其中指令用于电子邮件字段

<div class="form-group" formGroupName="localAccountData">
    <label>Emailadres</label>
    <input formControlName="email"
           type="text" 
           class="form-control"
           placeholder="Email (login)"
           bindQueryParamToInput="e">
</div>

component.ts 表单初始化的地方

@Component({
  selector: 'gimmi-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
  registrationForm: FormGroup;

  constructor( ) { }

  ngOnInit(): void {
    this.registrationForm = new FormGroup ({
      'personData': new FormGroup({
        'firstName': new FormControl(null, Validators.required),
        'lastName': new FormControl(null, Validators.required),
        'birthday': new FormControl(null, Validators.required)
      }),
      'localAccountData': new FormGroup({
        'email': new FormControl(null, [Validators.required, Validators.email]),
        'password': new FormControl(null, [Validators.required])
      })
    });
  }
}

编辑:接受的解决方案适用于上述情况。但是现在我把电子邮件字段放在一个单独的组件中(该指令现在在子组件中使用)现在 ExpressionChangedAfterItHasBeenCheckedError 又回来了... :-(

我已经尝试使用该解决方案并在子组件的 ngOnInit 中添加 this.ref.detectChanges(),但是没有用...

我需要做些什么来解决子组件中的这个问题吗?

子组件电子邮件-input.ts

import { Component, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'email-input',
  templateUrl: './email-input.component.html',
  styleUrls: ['./email-input.component.css']
})
export class EmailInputComponent implements OnInit {
  @Input() parentFormGroup: FormGroup;

  constructor() { }

  ngOnInit(): void {
    this.parentFormGroup.addControl( 'email', new FormControl(null, [Validators.required, Validators.email]));
  }
}

subcomponent email-input.html(使用指令的地方)

div [formGroup]='parentFormGroup'>
        <input  formControlName="email" 
                type="text" 
                class="form-control" 
                placeholder="Email (login)" 
                bindQueryParamToInput="e">
</div>

在component.html中,我现在只使用<email-input></email-input>组件。

另一个“标准”解决方案是命令更改检测。

  constructor( private ngControl : NgControl, private ref: ChangeDetectorRef) { }

  ngOnInit() {
    const queryParams = new URLSearchParams(location.search);

    if (queryParams.has(this.paramKey)) {
      this.ngControl.control.patchValue(queryParams.get(this.paramKey));
      this.ref.markForCheck();

      // or, alternatively
      this.ref.detectChanges();
    }
  }

我通过更改在更新表单控件值的行周围放置 setTimeout 解决了我在编辑中描述的问题。

setTimeout(() => {
  this.ngControl.control.patchValue(queryParams.get(this.paramKey));
});

这可行,但感觉像是一种变通方法,而不是可靠的解决方案... 因此,非常感谢任何有助于获得更好解决方案的帮助