Angular Material自动完成组件添加失焦验证后筛选功能异常
Angular Material自动完成组件添加失焦验证后筛选功能异常
我来帮你分析并解决这个问题哈~
问题原因拆解
你现在遇到的核心问题是:加了失焦(blur)验证后,Autocomplete的筛选没有在输入时实时触发,反而要等失焦才生效。主要是这几个点导致的:
- 模板里直接调用
filterNames函数生成选项列表,这种方式依赖Angular的变更检测时机,而你的onChange事件不仅没处理筛选逻辑,还存在语法错误(比如变量名重复、大写的I应该是小写i),导致输入时根本没触发筛选更新。 onBlur里的updateValueAndValidity()会强制更新控件状态,间接让筛选逻辑只有在失焦时才会被触发。- 没有利用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
相关产品推荐
相关产品推荐

