Angular表单:FormBuilder实现必填字段校验提示失效求助
Angular表单必填提示不显示的修复方案
你的代码存在几个关键问题,导致必填提示无法正常渲染,以下是具体问题和修复方案:
核心问题分析
- 表单结构混乱:同时定义了独立的
creditFormGroup和profileForm内部的credit分组,且ngOnInit还重新覆盖了credit变量,但模板绑定的是profileForm,导致你在getter里获取的montantDuPret和实际表单里的控件完全无关。 - FormArray使用错误:
aliases被定义为单个FormControl的数组,但你需要的是每个贷款条目对应一个完整的FormGroup(包含typeDePret、montantDuPret等字段),当前结构完全不符合需求。 - 控件绑定错误:模板里的输入框同时设置了
[formControlName]="i"和formControlName="montantDuPret",属性重复且逻辑错误;另外FormArray没有嵌套FormGroup,导致无法正确绑定多个字段。 - 验证器配置错误:
montantDuPret的验证器写法错误(初始值位置放了验证器),还错误地用了邮箱正则匹配金额字段,完全不符合场景。 - 校验状态判断错误:模板里的
*ngIf判断的是独立credit里的控件状态,不是当前FormArray条目中的控件,自然不会触发提示。
修复后的代码
TypeScript代码
import { Component } from '@angular/core'; import { FormControl, FormGroup, Validators, FormArray, FormBuilder} from '@angular/forms'; @Component({ selector: 'app-chargement-du-questionnaire', templateUrl: './chargement-du-questionnaire.component.html', styleUrls: ['./chargement-du-questionnaire.component.css'] }) export class ChargementDuQuestionnaireComponent { errorMessage: string = ""; profileForm: FormGroup; constructor(private fb: FormBuilder) { // 初始化表单,aliases是FormGroup的数组 this.profileForm = this.fb.group({ aliases: this.fb.array([ this.createCreditFormGroup() // 初始化第一个贷款条目 ]) }); } // 创建单个贷款的FormGroup,包含所有字段和验证规则 createCreditFormGroup(): FormGroup { return this.fb.group({ typeDePret: ['', Validators.required], montantDuPret: ['', [Validators.required, Validators.pattern('^[0-9]+$')]], // 金额用数字正则 tauxDuPret: ['', Validators.required], dureeDuPretAn: ['', Validators.required], dureeDuPretMois: ['', Validators.required], dontDiffere: ['', Validators.required] }); } // 获取aliases FormArray get aliasArray() { return this.profileForm.get('aliases') as FormArray; } // 获取指定索引的贷款FormGroup getCreditFormGroup(index: number): FormGroup { return this.aliasArray.at(index) as FormGroup; } addAlias() { if (this.aliasArray.length === 3) { this.errorMessage = "最多添加3个贷款"; setTimeout(() => { window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); }, 10); } else { this.errorMessage = ""; this.aliasArray.push(this.createCreditFormGroup()); setTimeout(() => { window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); }, 10); } } removeAlias(index: number) { if (this.aliasArray.length === 3) { this.errorMessage = ""; } this.aliasArray.removeAt(index); } }
HTML代码
<form [formGroup]="profileForm" class="needs-validation" novalidate> <div formArrayName="aliases"> <div class="form" *ngFor="let alias of aliasArray.controls; let i=index" [formGroupName]="i"> <p> Pret n°{{i+1}}</p> <div> <label for="typeDePret-{{i}}">Type de prêt:</label><br> <select class="form-select" aria-label="Default select example" id="typeDePret-{{i}}" formControlName="typeDePret"> <option value="">请选择贷款类型</option> <option value="1">Prêt classique (amortissable)</option> <option value="2">In fine</option> <option value="3">Prêt à taux Zéro</option> <option value="4">Prêt relais</option> </select> <div class="invalid-feedback" *ngIf="getCreditFormGroup(i).get('typeDePret')?.invalid && getCreditFormGroup(i).get('typeDePret')?.touched"> 请选择贷款类型 </div> </div> <label for="montantDuPret-{{i}}">Montant du prêt</label><br> <div class="input-group mb-3"> <input id="montantDuPret-{{i}}" type="text" formControlName="montantDuPret" class="form-control" aria-label="Amount"> <span class="input-group-text">.00 €</span> <div class="invalid-feedback" *ngIf="getCreditFormGroup(i).get('montantDuPret')?.invalid && getCreditFormGroup(i).get('montantDuPret')?.touched"> <div *ngIf="getCreditFormGroup(i).get('montantDuPret')?.errors?.['required']"> 请输入贷款金额 </div> <div *ngIf="getCreditFormGroup(i).get('montantDuPret')?.errors?.['pattern']"> 金额必须为数字 </div> </div> </div> <label for="tauxDuPret-{{i}}">Taux du prêt</label><br> <div class="input-group mb-3"> <input id="tauxDuPret-{{i}}" type="text" formControlName="tauxDuPret" class="form-control" aria-label="Amount"> <span class="input-group-text">%</span> <div class="invalid-feedback" *ngIf="getCreditFormGroup(i).get('tauxDuPret')?.invalid && getCreditFormGroup(i).get('tauxDuPret')?.touched"> 请输入贷款利率 </div> </div> <label for="dureeDuPret-{{i}}">Durée totale</label><br> <div class="input-group mb-3"> <input id="dureeDuPretAn-{{i}}" type="text" formControlName="dureeDuPretAn" class="form-control" aria-label="Years"> <span class="input-group-text">an(s)</span> <input id="dureeDuPretMois-{{i}}" type="text" formControlName="dureeDuPretMois" class="form-control" aria-label="Months"> <span class="input-group-text">mois</span> <div class="invalid-feedback" *ngIf="getCreditFormGroup(i).get('dureeDuPretAn')?.invalid && getCreditFormGroup(i).get('dureeDuPretAn')?.touched"> 请输入年数 </div> <div class="invalid-feedback" *ngIf="getCreditFormGroup(i).get('dureeDuPretMois')?.invalid && getCreditFormGroup(i).get('dureeDuPretMois')?.touched"> 请输入月数 </div> </div> <label for="dontDiffere-{{i}}">Dont différé</label><br> <select class="form-select" aria-label="Default select example" id="dontDiffere{{i}}" formControlName="dontDiffere"> <option value="">请选择延期时长</option> <option value="1">1 mois</option> <option value="2">2 mois</option> <option value="3">3 mois</option> <option value="4">4 mois</option> <option value="5">5 mois</option> <option value="6">6 mois</option> <option value="7">7 mois</option> <option value="8">8 mois</option> <option value="9">9 mois</option> <option value="10">10 mois</option> <option value="11">11 mois</option> <option value="12">12 mois</option> <option value="13">13 mois</option> <option value="14">14 mois</option> <option value="15">15 mois</option> <option value="16">16 mois</option> <option value="17">17 mois</option> <option value="18">18 mois</option> <option value="19">19 mois</option> <option value="20">20 mois</option> <option value="21">21 mois</option> <option value="22">22 mois</option> <option value="23">23 mois</option> <option value="24">24 mois</option> </select> <div class="invalid-feedback" *ngIf="getCreditFormGroup(i).get('dontDiffere')?.invalid && getCreditFormGroup(i).get('dontDiffere')?.touched"> 请选择延期时长 </div> <button (click)="removeAlias(i)">删除此贷款</button> </div> </div> <div class="error" *ngIf="errorMessage">{{errorMessage}}</div> <button type="button" (click)="addAlias()">+ 添加另一个贷款</button> </form>
修复说明
- 重构了表单结构,
aliases改为FormGroup数组,每个条目对应完整的贷款字段 - 统一使用
profileForm作为唯一表单实例,删除了冗余的独立credit变量 - 修正了验证器的写法,给金额字段替换了数字正则,移除了错误的邮箱验证
- 模板中使用
[formGroupName]="i"绑定FormArray中的每个FormGroup,确保字段绑定正确 - 通过
getCreditFormGroup(index)方法获取对应条目的控件,正确判断校验状态 - 给所有必填字段添加了空选项,确保用户选择时能触发校验
内容的提问来源于stack exchange,提问作者Abate Raphael
相关产品推荐
相关产品推荐

