You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular Material中调用FormControl的setErrors后错误不即时显示

解决Angular Material中setErrors后错误消息不即时显示的问题

问题分析

你遇到的核心问题是:调用setErrors后,mat-error不会即时渲染,只有清空输入才会显示错误状态。这主要是因为:

  1. displayFn是Angular Material自动完成组件用来格式化选项文本的方法,在这里处理异步请求会导致时机不对,且会被频繁触发重复请求;
  2. mat-error默认仅在控件invalid且touched/dirty时显示,你当前的代码没有正确标记控件状态;
  3. 手动调用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>

方案二:手动修复现有逻辑(不推荐,仅适配现有代码)

如果暂时不想重构为异步验证器,可通过以下步骤修复:

  1. 将验证逻辑移到合适时机:从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
    }
  );
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:33:46