在 ngOnInit 中添加验证器时出现 ExpressionChangedAfterItHasBeenCheckedError
ExpressionChangedAfterItHasBeenCheckedError when add validator in ngOnInit
我正在尝试向输入添加自定义验证器,但是当我这样做时它会触发 ExpressionChangedAfterItHasBeenCheckedError 错误,说明某些内容从 TRUE 变为 FALSE。
我将问题追溯到以下行:
ngOnInit(): void {
this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
}
如果我删除 TabValidator.ipaddress() 那么错误就会消失。同样,如果我的验证器强制 return of 'null',那么错误就会消失。我的验证器如下:
private static _ipaddress(address: string): any {
console.log('checking ip address: '+address+' valid: '+ip.isV4Format(address)+' is null: '+(address === null ? 'yes' : 'no'));
if (!ip.isV4Format(address)) { return { 'wrongFormat': true }; }
console.log('returning null');
return null;
}
public static ipaddress(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
console.log('validator returning: '+TabValidator._ipaddress(control.value));
return TabValidator._ipaddress(control.value);
};
}
从控制台日志来看,验证器似乎每次都return输入相同的值。
有人可以解释这里出了什么问题吗?我无法解释什么变量从 'true' 变为 'false',因为上面的行中没有涉及布尔值。验证器如何 return 不同的值而不出现在我的控制台日志中?
我读到一个关于不在 ngOnInit 中做事的 SO 问题,但这似乎是一个转移注意力的问题。
更新:我尝试过:
ngOnInit(): void {
Promise.resolve().then(() => {
this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
});
}
还有
ngOnInit(): void {
setTimeout(() => this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()])), 10);
}
但随后错误变为:
ERROR Error: Cannot find control with name: 'gateway'
解决方案:
我将其追溯到一个错误 - 使用反应式表单 + 验证器 + ngb 选项卡。将验证器添加到选项卡上的控件会导致错误。唯一的解决办法是改成模板形式。
如果您查看 angular 的 github 问题页面,您可以找到与您遇到的相同问题相关的几张票(例如 https://github.com/angular/angular/issues/15634,还有更多,这一张我刚刚发现作为例子)。长话短说:angular 不喜欢某些(全部?)生命周期挂钩中的视图更改。在您的特定情况下究竟发生了什么变化:我假设这是 formField 的有效性状态(即在 Angular 的控制代码内部,您无权访问),它在内部触发更改检测...
如果可以,请将 this.ipv4Fields.addControl()
移至构造函数。如果那不可能 - 请参阅 github 票中的建议(执行 detectChanges
、或 Promise
、或 setTimeout
等)...
更新:
@Component(){}
export class MyComponent implements OnInit{
@Input()
ipv4Fields: FormGroup;
//inject `ChangeDetecorRef`
constructor(protected changeDetectorRef: ChangeDetectorRef){
}
ngOnInit(){
this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
this.changeDetectorRef.detectChanges();
}
}
我正在尝试向输入添加自定义验证器,但是当我这样做时它会触发 ExpressionChangedAfterItHasBeenCheckedError 错误,说明某些内容从 TRUE 变为 FALSE。
我将问题追溯到以下行:
ngOnInit(): void {
this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
}
如果我删除 TabValidator.ipaddress() 那么错误就会消失。同样,如果我的验证器强制 return of 'null',那么错误就会消失。我的验证器如下:
private static _ipaddress(address: string): any {
console.log('checking ip address: '+address+' valid: '+ip.isV4Format(address)+' is null: '+(address === null ? 'yes' : 'no'));
if (!ip.isV4Format(address)) { return { 'wrongFormat': true }; }
console.log('returning null');
return null;
}
public static ipaddress(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
console.log('validator returning: '+TabValidator._ipaddress(control.value));
return TabValidator._ipaddress(control.value);
};
}
从控制台日志来看,验证器似乎每次都return输入相同的值。
有人可以解释这里出了什么问题吗?我无法解释什么变量从 'true' 变为 'false',因为上面的行中没有涉及布尔值。验证器如何 return 不同的值而不出现在我的控制台日志中?
我读到一个关于不在 ngOnInit 中做事的 SO 问题,但这似乎是一个转移注意力的问题。
更新:我尝试过:
ngOnInit(): void {
Promise.resolve().then(() => {
this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
});
}
还有
ngOnInit(): void {
setTimeout(() => this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()])), 10);
}
但随后错误变为:
ERROR Error: Cannot find control with name: 'gateway'
解决方案:
我将其追溯到一个错误 - 使用反应式表单 + 验证器 + ngb 选项卡。将验证器添加到选项卡上的控件会导致错误。唯一的解决办法是改成模板形式。
如果您查看 angular 的 github 问题页面,您可以找到与您遇到的相同问题相关的几张票(例如 https://github.com/angular/angular/issues/15634,还有更多,这一张我刚刚发现作为例子)。长话短说:angular 不喜欢某些(全部?)生命周期挂钩中的视图更改。在您的特定情况下究竟发生了什么变化:我假设这是 formField 的有效性状态(即在 Angular 的控制代码内部,您无权访问),它在内部触发更改检测...
如果可以,请将 this.ipv4Fields.addControl()
移至构造函数。如果那不可能 - 请参阅 github 票中的建议(执行 detectChanges
、或 Promise
、或 setTimeout
等)...
更新:
@Component(){}
export class MyComponent implements OnInit{
@Input()
ipv4Fields: FormGroup;
//inject `ChangeDetecorRef`
constructor(protected changeDetectorRef: ChangeDetectorRef){
}
ngOnInit(){
this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
this.changeDetectorRef.detectChanges();
}
}