从父组件动态设置子表单验证器
Dynamically Set SubForm Validators from the Parent component
我一直在 Angular 8 中创建可重用的子表单,使用 FormGroupDirective
为子项获取父项 FormGroup
的引用很容易完成,但是我很难弄清楚如何从父级动态设置子窗体上的验证器。
使用 ngAfterViewInit
我可以看到子表单的表单控件已添加到父表单,但我似乎无法直接从父表单更新默认的子表单验证器。
// PARENT COMPONENT
public ngAfterViewInit() {
// Form controls have been applied to the form group
console.log('ngAfterViewInit', this.form.value);
// BUT the validators of profile form aren't being set?
this.form.get('profile').get('description').setValidators([Validators.required]);
}
我创建了 StackBlitz 我的示例代码。除配置文件描述外的所有字段都是必填字段,并具有默认值。因此,如果不对验证器进行任何更改,表单将在提交时通过验证并在控制台中输出 VALID。在 ngAfterViewInit
中,我将描述字段验证器设置为必需,这应该可以防止提交表单并在控制台中输出 INVALID,但它仍然提交并输出 有效.
是否可以动态设置子表单的验证器而不通过 @Input
绑定传递它们?
显然,您只需在已更改的表单控件上使用 updateValueAndValidity
。
this.form.get('profile').get('description').updateValueAndValidity();
所以最后看起来像这样:
public ngAfterViewInit() {
// Form controls will now exist
console.log('ngAfterViewInit', this.form.value);
// BUT the validators of the profile form should not allow submission if set to required, and they do?
this.form.get('profile').get('description').setValidators([Validators.required]);
this.form.get('profile').get('description').updateValueAndValidity();
}
执行此操作时,您会在控制台中收到一条错误消息:
ERROR
Error: ExpressionChangedAfterItHasBeenCheckedError:
Expression has changed after it was checked.
Previous value: 'ng-valid: true'. Current value: 'ng-valid: false'.
可以通过使用 ChangeDetectorRef
并调用 this.changeDetector.detectChanges()
或将父组件的更改检测策略更新为 ChagneDetectionStrategy.OnPush
.
来解决这个问题
constructor(private changeDetector: ChangeDetectorRef) { }
// Removed for brevity
public ngAfterViewInit() {
const descControl = this.form.get('profile').get('description');
descControl.setValidators([Validators.required]);
descControl.updateValueAndValidity();
this.changeDetector.detectChanges();
}
@Component({
selector: 'app-page',
templateUrl: './page.component.html',
styleUrls: ['./page.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageComponent implements OnInit, AfterContentInit, AfterViewInit {
// Removed for brevity
public ngAfterViewInit() {
const descControl = this.form.get('profile').get('description');
descControl.setValidators([Validators.required]);
descControl.updateValueAndValidity();
}
}
我一直在 Angular 8 中创建可重用的子表单,使用 FormGroupDirective
为子项获取父项 FormGroup
的引用很容易完成,但是我很难弄清楚如何从父级动态设置子窗体上的验证器。
使用 ngAfterViewInit
我可以看到子表单的表单控件已添加到父表单,但我似乎无法直接从父表单更新默认的子表单验证器。
// PARENT COMPONENT
public ngAfterViewInit() {
// Form controls have been applied to the form group
console.log('ngAfterViewInit', this.form.value);
// BUT the validators of profile form aren't being set?
this.form.get('profile').get('description').setValidators([Validators.required]);
}
我创建了 StackBlitz 我的示例代码。除配置文件描述外的所有字段都是必填字段,并具有默认值。因此,如果不对验证器进行任何更改,表单将在提交时通过验证并在控制台中输出 VALID。在 ngAfterViewInit
中,我将描述字段验证器设置为必需,这应该可以防止提交表单并在控制台中输出 INVALID,但它仍然提交并输出 有效.
是否可以动态设置子表单的验证器而不通过 @Input
绑定传递它们?
显然,您只需在已更改的表单控件上使用 updateValueAndValidity
。
this.form.get('profile').get('description').updateValueAndValidity();
所以最后看起来像这样:
public ngAfterViewInit() {
// Form controls will now exist
console.log('ngAfterViewInit', this.form.value);
// BUT the validators of the profile form should not allow submission if set to required, and they do?
this.form.get('profile').get('description').setValidators([Validators.required]);
this.form.get('profile').get('description').updateValueAndValidity();
}
执行此操作时,您会在控制台中收到一条错误消息:
ERROR
Error: ExpressionChangedAfterItHasBeenCheckedError:
Expression has changed after it was checked.
Previous value: 'ng-valid: true'. Current value: 'ng-valid: false'.
可以通过使用 ChangeDetectorRef
并调用 this.changeDetector.detectChanges()
或将父组件的更改检测策略更新为 ChagneDetectionStrategy.OnPush
.
constructor(private changeDetector: ChangeDetectorRef) { }
// Removed for brevity
public ngAfterViewInit() {
const descControl = this.form.get('profile').get('description');
descControl.setValidators([Validators.required]);
descControl.updateValueAndValidity();
this.changeDetector.detectChanges();
}
@Component({
selector: 'app-page',
templateUrl: './page.component.html',
styleUrls: ['./page.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageComponent implements OnInit, AfterContentInit, AfterViewInit {
// Removed for brevity
public ngAfterViewInit() {
const descControl = this.form.get('profile').get('description');
descControl.setValidators([Validators.required]);
descControl.updateValueAndValidity();
}
}