Angular 10 Reactive Form按条件隐藏输入项后表单无法提交问题
问题根因
Angular响应式表单的校验逻辑和控件是否在DOM中渲染无关,你初始化表单时同时给firstName和lastName都加了Validators.required必填校验,就算用*ngIf隐藏了其中一个输入框,对应的表单控件依然存在且处于必填校验生效的状态,隐藏的控件值为空就会导致整个表单校验不通过,无法提交。
解决步骤
1. 修改app.component.ts逻辑
需要在切换单选框的时候,动态给对应控件增加/移除必填校验,同时更新控件的校验状态:
import { Component } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ReCaptchaV3Service } from 'ngx-captcha'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'testproject'; registerForm: FormGroup; siteKey: any; submitted = false; firstNames = true; constructor(private formBuilder: FormBuilder, private reCaptchaV3Service: ReCaptchaV3Service) { } ngOnInit() { this.registerForm = this.formBuilder.group({ title: ['', Validators.required], firstName: ['', Validators.required], // 初始隐藏lastName,所以初始不加必填校验 lastName: [''] }); } showFirstName(){ this.firstNames = true; // 给firstName加必填,移除lastName的必填 this.registerForm.get('firstName').addValidators(Validators.required); this.registerForm.get('lastName').removeValidators(Validators.required); // 更新两个控件的校验状态 this.registerForm.get('firstName').updateValueAndValidity(); this.registerForm.get('lastName').updateValueAndValidity(); } showLastName(){ this.firstNames = false; // 给lastName加必填,移除firstName的必填 this.registerForm.get('lastName').addValidators(Validators.required); this.registerForm.get('firstName').removeValidators(Validators.required); // 更新两个控件的校验状态 this.registerForm.get('lastName').updateValueAndValidity(); this.registerForm.get('firstName').updateValueAndValidity(); } get f() { return this.registerForm.controls; } onSubmit() { this.submitted = true; if (this.registerForm.invalid) { return; } // 提交的时候过滤掉未选中的字段 const submitValue = {...this.registerForm.value}; if (this.firstNames) { delete submitValue.lastName; } else { delete submitValue.firstName; } alert('提交成功! :-)\n' + JSON.stringify(submitValue, null, 4)); } onReset() { this.submitted = false; this.firstNames = true; // 重置的时候恢复初始校验状态 this.registerForm.get('firstName').addValidators(Validators.required); this.registerForm.get('lastName').removeValidators(Validators.required); this.registerForm.reset(); } }
2. 修改app.component.html的对应问题
修正单选框的点击事件绑定、文字错误以及选中状态默认值:
<div class="card m-3"> <h5 class="card-header">Angular 10 响应式表单校验</h5> <div class="card-body"> <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> <div class="form-row"> <div class="form-group col"> <label>称谓</label> <select formControlName="title" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.title.errors }"> <option value=""></option> <option value="Mr">先生</option> <option value="Mrs">夫人</option> <option value="Miss">小姐</option> <option value="Ms">女士</option> </select> <div *ngIf="submitted && f.title.errors" class="invalid-feedback"> <div *ngIf="f.title.errors.required">称谓为必填项</div> </div> </div> <div ><input (click)="showFirstName()" name="fname" type="radio" [checked]="firstNames"> 显示名字</div> <div ><input (click)="showLastName()" name="fname" type="radio" [checked]="!firstNames"> 显示姓氏</div> <div class="form-group col-5" *ngIf="firstNames"> <label>名字</label> <input type="text" formControlName="firstName" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.firstName.errors }" /> <div *ngIf="submitted && f.firstName.errors" class="invalid-feedback"> <div *ngIf="f.firstName.errors.required">名字为必填项</div> </div> </div> <div class="form-group col-5" *ngIf="!firstNames"> <label>姓氏</label> <input type="text" formControlName="lastName" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.lastName.errors }" /> <div *ngIf="submitted && f.lastName.errors" class="invalid-feedback"> <div *ngIf="f.lastName.errors.required">姓氏为必填项</div> </div> </div> </div> <div class="text-center"> <button class="btn btn-primary mr-1">注册</button> <button class="btn btn-secondary" type="reset" (click)="onReset()">取消</button> </div> </form> </div> </div>
可选优化方案
也可以选择动态增删表单控件的方式实现,切换单选框的时候用addControl和removeControl方法增减对应控件,不需要手动处理校验状态,逻辑更简洁。
内容的提问来源于stack exchange,提问作者uiankosh
相关产品推荐
相关产品推荐

