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

Angular Material自动完成组件添加失焦验证后筛选功能异常

Angular Material自动完成组件添加失焦验证后筛选功能异常

我来帮你分析并解决这个问题哈~

问题原因拆解

你现在遇到的核心问题是:加了失焦(blur)验证后,Autocomplete的筛选没有在输入时实时触发,反而要等失焦才生效。主要是这几个点导致的:

  1. 模板里直接调用filterNames函数生成选项列表,这种方式依赖Angular的变更检测时机,而你的onChange事件不仅没处理筛选逻辑,还存在语法错误(比如变量名重复、大写的I应该是小写i),导致输入时根本没触发筛选更新。
  2. onBlur里的updateValueAndValidity()会强制更新控件状态,间接让筛选逻辑只有在失焦时才会被触发。
  3. 没有利用Angular表单控件的valueChanges来实时监听输入变化,反而依赖模板函数被动执行,很容易出现时机不对的情况。

修复方案

我给你调整了代码,分步骤来改:

1. 修正TS文件逻辑,添加实时筛选监听

首先我们要给每个表单控件加valueChanges订阅,实时更新筛选后的选项列表,同时修复原有的语法错误:

// 新增一个对象,存储每行对应的筛选后名称列表,保证每行筛选独立
filteredNamesMap: {[key: number]: string[]} = {};

ngOnInit() {
  // 初始化时给每个表单控件绑定值变化监听
  this.form.controls.forEach((control, index) => {
    const nameControl = control.get('name');
    nameControl?.valueChanges.subscribe((inputValue) => {
      // 实时根据输入值筛选列表
      this.filteredNamesMap[index] = this.namesList.filter(item => 
        item.toLowerCase().includes(inputValue?.toLowerCase() || '')
      );
    });
    // 初始化时默认显示全量列表
    this.filteredNamesMap[index] = [...this.namesList];
  });
}

// 修复原onChange里的语法错误,移除无关干扰逻辑
onChange(data: { value: { name: string; id: number; city: string } }, index: number) {
  const i = this.modifiedArray.findIndex(x => x === data.value.id);
  if (data.value.id) {
    // 变量名不要和参数重复,改成targetData
    const targetData = this.data.find(x => x.id === data.value.id);
    if (i !== -1) { // 原代码里的大写I改成小写i
      this.modifiedArray.splice(i, 1);
    }
  }
}

onBlur(index: number, controlName: string) {
  const control = this.form.at(index).get(controlName);
  control?.markAsTouched();
  // 移除updateValueAndValidity(),输入时控件值已实时更新,失焦只需要标记为已触碰即可
  // control?.updateValueAndValidity();
}

onOptionSelected(index: number, controlName: string) {
  const control = this.form.at(index).get(controlName);
  control?.markAsTouched();
}

// 移除原来的filterNames函数,改用我们定义的filteredNamesMap

2. 调整模板代码,绑定实时筛选列表

把模板里的*ngFor从调用filterNames改成绑定到filteredNamesMap[index],这样输入时就能实时拿到更新后的选项:

<td mat-cell *matCellDef="let element; let id = index;" [formGroup]="element" [formGroupName]="id">
  <input 
    type="text" 
    [matAutocomplete]="auto" 
    formControlName="name" 
    (blur)="onBlur(id, 'name')" 
    (optionSelected)="onOptionSelected(id, 'name')"
    <!-- 移除onChange事件,改用表单valueChanges监听更可靠 -->
  />
  <mat-autocomplete #auto="matAutocomplete">
    <mat-option 
      (mousedown)="$event.preventDefault()" 
      *ngFor="let data of filteredNamesMap[id]" 
      [value]="data"
    >
      {{ data }}
    </mat-option>
  </mat-autocomplete>
</td>

额外说明

  • 为什么移除onChange事件?因为Angular表单的valueChanges监听更稳定,能自动处理值的变化,原有的onChange不仅有语法错误,还会干扰正常的筛选逻辑。
  • filteredNamesMap用来存储每行独立的筛选结果,避免不同行的筛选互相影响。
  • 失焦时只做markAsTouched()就够了,不需要强制更新值和验证状态,这样就不会把筛选的触发时机拖到失焦时了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:05:30