如何在强类型FormGroup中实现嵌套可选(可空)子FormGroup?
Angular 强类型 FormGroup 动态可选组验证问题
定义的强类型表单接口
export interface BasicForm { id: FormControl<string | null>; setting: FormControl<number>; optionalGroup: FormGroup<OptionalGroup | null>; // setting不为1时设为null } export interface OptionalGroup { id: FormControl<string>; name: FormControl<string>; }
表单初始化代码
this.formBuilder.group<BasicForm>( { id: new FormControl(''), setting: new FormControl(0, { nonNullable: true, validators: Validators.required, }), optionalGroup: this.formBuilder.group<OptionalGroup>({ id: new FormControl('', { nonNullable: true, validators: Validators.required, }), name: new FormControl('', { nonNullable: true, validators: Validators.required, }), }) as FormGroup<OptionalGroup | null>, }, { validators: [optionalGroupValidator(this.formBuilder)], } );
需求
实现动态逻辑:
- 当
setting值为1时,optionalGroup为必填项 - 当
setting值不为1时,optionalGroup设为null或被省略,调用getRawValue()时能得到对应结果
当前问题
自定义Validator逻辑混乱,不清楚该移除控件还是设为非必填,无法实现预期效果:
export function optionalGroupValidator(formBuilder: FormBuilder): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const basicForm = control as FormGroup<BasicForm>; const validatorErrors: ValidationErrors = {}; if (basicForm.controls.setting.value === 1) { const newForm = formBuilder.group<OptionalGroup>({ id: new FormControl('', { nonNullable: true, validators: Validators.required, }), name: new FormControl('', { nonNullable: true, validators: Validators.required, }), }); //Add the formback or? // basicForm.addControl('optionalGroup', newForm); } else { //basicForm.controls.optionalGroup.setValue(null); } console.log(basicForm); return validatorErrors; }; }
解决方案
核心思路
Validator只负责验证逻辑,表单结构/值的动态变更通过监听setting的valueChanges实现,避免在Validator中修改表单结构。
修改后的代码实现
1. 调整表单初始化
初始时将optionalGroup设为null:
this.form = this.formBuilder.group<BasicForm>({ id: new FormControl(''), setting: new FormControl(0, { nonNullable: true, validators: Validators.required, }), optionalGroup: null as FormGroup<OptionalGroup> | null, }, { validators: [optionalGroupValidator()], });
2. 监听setting值变化,动态控制optionalGroup
this.form.controls.setting.valueChanges.subscribe(settingValue => { const optionalGroupControl = this.form.get('optionalGroup'); if (settingValue === 1) { // 创建并添加可选组 const optionalGroup = this.formBuilder.group<OptionalGroup>({ id: new FormControl('', { nonNullable: true, validators: Validators.required, }), name: new FormControl('', { nonNullable: true, validators: Validators.required, }), }); this.form.setControl('optionalGroup', optionalGroup); optionalGroup.setValidators(Validators.required); } else { // 将可选组设为null并清除验证 this.form.patchValue({ optionalGroup: null }); optionalGroupControl?.clearValidators(); } // 更新验证状态 this.form.controls.optionalGroup?.updateValueAndValidity(); });
3. 修正自定义Validator,仅做验证
export function optionalGroupValidator(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const basicForm = control as FormGroup<BasicForm>; const settingValue = basicForm.controls.setting.value; const optionalGroup = basicForm.controls.optionalGroup; // setting为1时,检查可选组是否存在且有效 if (settingValue === 1 && (!optionalGroup || optionalGroup.invalid)) { return { optionalGroupRequired: '当setting为1时,必须填写可选组内容' }; } return null; }; }
效果验证
setting=1:optionalGroup自动创建并设为必填,未填写则表单验证失败setting≠1:optionalGroup设为null,调用getRawValue()时返回optionalGroup: null,符合预期
内容的提问来源于stack exchange,提问作者Marcel
相关产品推荐
相关产品推荐

