Angular Material中调用FormControl的setErrors后错误不即时显示
解决Angular Material中setErrors后错误消息不即时显示的问题
问题分析
你遇到的核心问题是:调用setErrors后,mat-error不会即时渲染,只有清空输入才会显示错误状态。这主要是因为:
displayFn是Angular Material自动完成组件用来格式化选项文本的方法,在这里处理异步请求会导致时机不对,且会被频繁触发重复请求;mat-error默认仅在控件invalid且touched/dirty时显示,你当前的代码没有正确标记控件状态;- 手动调用
updateValueAndValidity后,视图可能没有触发变更检测。
解决方案
方案一:使用AsyncValidator(推荐,符合Angular表单规范)
Angular提供了异步验证器机制,能自动处理验证状态更新,让mat-error自动响应错误状态。
1. 定义异步验证器
创建一个独立的验证器函数,封装SAP状态检查逻辑:
import { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { map, catchError } from 'rxjs/operators'; import { ContractService } from './你的服务路径'; export function sapSalesStatusValidator(contractService: ContractService): AsyncValidatorFn { return (control: AbstractControl): Observable<ValidationErrors | null> => { const registroVenta = control.value as RegistroVentaDto; if (!registroVenta?.registroVentaConsecutivo) { return of(null); } return contractService.getStatusSales(registroVenta.registroVentaConsecutivo).pipe( map(res => res ? null : { 'invalidSapStatus': true }), catchError(() => of(null)) // 可根据需求调整错误处理逻辑 ); }; }
2. 关联到FormControl
在组件中创建FormControl时,添加异步验证器:
import { FormControl, Validators } from '@angular/forms'; import { sapSalesStatusValidator } from './你的验证器路径'; // 组件内初始化表单控件 registroVentaControl = new FormControl(null, { validators: [Validators.required], asyncValidators: [sapSalesStatusValidator(this.contractService)], updateOn: 'change' // 可选:设置验证触发时机,如'blur'/'submit' });
3. 修改HTML中的错误提示
对应验证器的错误键,精准显示错误:
<mat-form-field appearance="outline" class="w-100"> <mat-label>Registro Venta</mat-label> <input type="text" placeholder="Buscar..." matInput (input)="setFilter(input.value)" [matAutocomplete]="auto" [formControl]="registroVentaControl" (keyup.enter)="addOption()" #input required /> <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn.bind(this)" (optionSelected)="optionSelected($event.option)"> <mat-option *ngFor="let option of registroVentaList" [value]="option"> {{option.displayRegistroVentaConsecutivo}} </mat-option> </mat-autocomplete> <mat-error *ngIf="registroVentaControl.hasError('required')"> El registro de venta es obligatorio </mat-error> <mat-error *ngIf="registroVentaControl.hasError('invalidSapStatus')"> El registro de venta no esta activo en SAP </mat-error> </mat-form-field>
方案二:手动修复现有逻辑(不推荐,仅适配现有代码)
如果暂时不想重构为异步验证器,可通过以下步骤修复:
- 将验证逻辑移到合适时机:从
displayFn移到optionSelected事件,避免频繁触发请求:
optionSelected(option: MatAutocompleteSelectedEvent) { const registroVenta = option.value as RegistroVentaDto; this.contractService.getStatusSales(registroVenta.registroVentaConsecutivo).subscribe( res => { if (res) { this.enableUpdateButton = true; this.registroVentaControl.setErrors(null); } else { this.notificationService.openError(`Registro de venta '${registroVenta.displayRegistroVentaConsecutivo}' no activo en SAP.`); this.registroVentaControl.setErrors({ 'invalid': true }); this.registroVentaControl.markAsTouched(); // 标记控件为已触摸 this.enableUpdateButton = false; } this.registroVentaControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); this.cdr.detectChanges(); // 手动触发变更检测,需注入ChangeDetectorRef } ); }
- 修改mat-error的显示条件:确保控件invalid且touched/dirty时显示:
<mat-error *ngIf="registroVentaControl.invalid && (registroVentaControl.touched || registroVentaControl.dirty)"> {{ registroVentaControl.hasError('required') ? 'El registro de venta es obligatorio' : 'El registro de venta no esta activo en SAP' }} </mat-error>
内容的提问来源于stack exchange,提问作者Jorge Zapata
相关产品推荐
相关产品推荐

