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

Angular响应式表单结合.NET Core Web API实现标题唯一性校验异常问题

问题根因

你当前使用同步校验器承载异步HTTP校验逻辑,HTTP请求为非阻塞异步操作,校验函数执行return语句时接口尚未返回结果,你拿到的this.isExist是上一次校验的缓存值,因此出现校验结果颠倒的问题。此外将校验结果存在全局实例属性this.isExist还会引发并发问题,用户快速输入时多个请求先后返回会导致结果错乱。

解决方案

改用Angular提供的异步校验器实现远程校验逻辑,步骤如下:

  1. 修改校验服务,返回异步校验器实例
import { AsyncValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

uniqueTitleValidator(): AsyncValidatorFn {
  return (control: AbstractControl): Observable<ValidationErrors | null> => { 
    if(!control.value?.trim()) {
      return new Observable(sub => sub.next(null));
    }
    // 直接返回Http请求的Observable,Angular会自动订阅处理
    return this.albumService.uniqueTitleValidate(control.value).pipe(
      map((isExist: boolean) => {
        return isExist ? { titleAlreadyExists: {value: control.value} } : null;
      })
    );
  };
}
  1. 修改表单配置,将异步校验器放到asyncValidators配置项中,建议修改updateOn为blur减少不必要的接口请求
ngOnInit(): void {
  this.albumForm  = this.formBuilder.group({
    id: [Guid.EMPTY],
    title: ['', {
      // 同步校验器保留在validators数组
      validators: [
        Validators.required,
        Validators.maxLength(15),
        Validators.pattern("^[a-zA-Z0-9\' \'-'_\s]*")
      ],
      // 异步校验器单独放在asyncValidators数组
      asyncValidators: [this.titleValidator.uniqueTitleValidator()],
      // 失去焦点时才触发校验,避免每次输入都发请求
      updateOn: 'blur'
    }],
    description: ['']
  });
  if(this.formData){
    this.albumForm.patchValue(this.formData)
  }
}
  1. 可选优化:增加校验中状态提示,优化用户体验
    在HTML模板的错误提示区域增加pending状态判断:
<div *ngIf="title.invalid && (title.dirty || title.touched)" class="error">
  <!-- 新增校验中提示 -->
  <div *ngIf="title.pending">
    正在校验标题是否存在,请稍候...
  </div>
  <!-- 原有校验提示保持不变 -->
  <div *ngIf="title.errors?.required">
    Title is required. 
  </div>
  <div *ngIf="title.errors.maxlength">
      Title should be under 15 characters.
  </div>
  <div *ngIf="title.errors?.pattern">
      Only A-Z, a-z, 0-9, ' ', '-', '_' characters are allowed.
  </div>
  <div *ngIf="title.errors?.titleAlreadyExists">
     Album already exists.
  </div>
</div>
  1. 可选后端兼容:编辑场景下排除当前记录避免无法提交
    如果你需要支持编辑专辑的场景,后端校验时需要排除当前正在编辑的记录,避免原有标题无法通过校验:
[HttpGet]
[Route("api/albums/validation")]
public async Task<IActionResult> CheckTitle(string title, Guid? id = null)
{
        var album = await _albumService.GetAlbumByTitleAsync(title);
        // 若查询到的专辑就是当前正在编辑的专辑,判定为不重复
        if (album != null && (!id.HasValue || album.Id != id.Value))
            return Ok(true);
        return Ok(false);
}

内容的提问来源于stack exchange,提问作者D. B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 05:39:04