Angular 14 至多一个表单验证器开发求助
Angular 14 “至多一个”表单组验证器实现
核心思路
放弃通过启用/禁用字段的方式控制,直接给FormGroup添加自定义验证器,通过统计指定控件中有效且非空的数量,判断是否恰好为1,以此验证表单合法性。这种方式不会修改控件状态,从根源避免无限循环问题。
自定义验证器代码
创建独立的验证器文件(比如at-most-one.validator.ts):
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; export function atMostOneValidator(controlNames: string[]): ValidatorFn { return (group: AbstractControl): ValidationErrors | null => { const validFilledCount = controlNames.reduce((count, name) => { const control = group.get(name); // 仅统计有效且非空(去除首尾空白后不为空)的控件 if (control && control.valid && control.value?.toString().trim()) { return count + 1; } return count; }, 0); return validFilledCount === 1 ? null : { atMostOne: true }; }; }
在表单中使用
在组件中创建FormGroup时,将验证器添加到组的验证配置中:
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { atMostOneValidator } from './at-most-one.validator'; @Component({ selector: 'app-my-form', templateUrl: './my-form.component.html' }) export class MyFormComponent implements OnInit { myForm: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit(): void { this.myForm = this.fb.group({ email: ['', [Validators.email]], phone: ['', [Validators.pattern(/^\+?\d{10,15}$/)]], wechat: [''] }, { validators: atMostOneValidator(['email', 'phone', 'wechat']) }); } }
模板中的错误提示
在模板中根据表单的错误状态显示提示:
<form [formGroup]="myForm" (ngSubmit)="onSubmit()"> <div> <label>邮箱:</label> <input formControlName="email" type="email" placeholder="请输入邮箱"> <span *ngIf="myForm.get('email')?.invalid && myForm.get('email')?.touched"> 请输入有效的邮箱 </span> </div> <div> <label>手机号:</label> <input formControlName="phone" type="tel" placeholder="请输入手机号"> <span *ngIf="myForm.get('phone')?.invalid && myForm.get('phone')?.touched"> 请输入有效的手机号 </span> </div> <div> <label>微信号:</label> <input formControlName="wechat" placeholder="请输入微信号"> </div> <div *ngIf="myForm.hasError('atMostOne') && myForm.touched" class="error"> 请仅填写邮箱、手机号、微信号中的一项 </div> <button type="submit" [disabled]="!myForm.valid">提交</button> </form>
为什么之前的方法会触发无限循环
启用/禁用控件会触发FormGroup的valueChanges或statusChanges事件,如果在这些事件的回调中再次修改控件的启用/禁用状态,会导致事件被反复触发,形成无限循环。而组验证器仅做状态判断,不修改控件属性,完全规避了这个问题。
内容的提问来源于stack exchange,提问作者Bartek Sobolewski
相关产品推荐
相关产品推荐

