动态添加MatInput后Material Autocomplete失效问题咨询
解决动态添加matInput后Autocomplete失效的问题
问题根源
你的代码存在三个核心问题:
- 所有输入框共用同一个
filteredOptions数组,监听的是整个serviceNamesFormArray的value变化,无法区分单个输入框的输入内容,过滤逻辑完全混乱。 *ngFor循环里重复使用了同一个模板引用变量#auto,导致多个Autocomplete实例冲突,只有第一个能正常工作。- 添加新输入框后,没有为新的FormControl绑定独立的过滤监听。
修改后的完整代码
HTML部分
<form [formGroup]="feasibilityForm" (ngSubmit)="onSubmit(feasibilityForm.value)" > <mat-form-field [style.width.%]="100" *ngFor="let service of serviceNames.controls; let i = index" > <mat-label> Service Activity </mat-label> <input [formControlName]="i" matInput type="text" [matAutocomplete]="auto{{i}}" /> <mat-autocomplete #auto{{i}}="matAutocomplete"> <mat-option *ngFor="let item of filteredOptions[i] | async" [value]="item.Service" > {{ item.Service }} </mat-option> </mat-autocomplete> <!-- 可选:添加删除按钮方便管理动态项 --> <button mat-icon-button (click)="removeServiceName(i)" matSuffix> <mat-icon>delete</mat-icon> </button> </mat-form-field> <button mat-flat-button color="accent" (click)="addServiceName()"> 添加新服务项 </button> <div class="form-element"> <button mat-flat-button color="primary" type="submit">提交</button> </div> </form>
TS部分
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormArray, FormControl } from '@angular/forms'; import { MyService } from './my.service'; import { Observable } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { options: any[] = []; feasibilityForm: any; filteredOptions: Observable<any[]>[] = []; // 每个输入框对应独立的Observable title = 'my-app'; constructor(private service: MyService, private formBuilder: FormBuilder) {} ngOnInit() { this.initForm(); this.getNames(); } initForm() { this.feasibilityForm = this.formBuilder.group({ serviceNames: this.formBuilder.array([this.createServiceControl()]), }); // 初始化第一个控件的过滤监听 this.setupFilter(0); } // 封装单个服务项的FormControl创建逻辑 createServiceControl(): FormControl { return this.formBuilder.control(''); } get serviceNames() { return this.feasibilityForm.get('serviceNames') as FormArray; } addServiceName() { const newIndex = this.serviceNames.push(this.createServiceControl()); // 为新添加的控件绑定过滤监听 this.setupFilter(newIndex - 1); } removeServiceName(index: number) { this.serviceNames.removeAt(index); this.filteredOptions.splice(index, 1); } onSubmit(value) { console.log(this.serviceNames.value); } // 为指定索引的控件设置独立的过滤逻辑 setupFilter(index: number) { this.filteredOptions[index] = this.serviceNames.at(index).valueChanges.pipe( startWith(''), // 初始显示全部选项 map(value => this.filterData(value)) ); } filterData(enteredData: string) { if (!enteredData) return this.options; return this.options.filter(item => item.Service.toLowerCase().includes(enteredData.toLowerCase()) ); } getNames() { this.service.getLocalData().subscribe((response: any) => { this.options = response; // 数据加载完成后更新所有控件的过滤结果 this.serviceNames.controls.forEach((_, index) => { this.setupFilter(index); }); }); } }
关键修改点说明
- 独立过滤数据源:用
filteredOptions数组存储每个输入框的过滤Observable,确保每个输入框的建议列表互不干扰。 - 单个控件监听:新增
setupFilter方法,为每个FormControl单独监听valueChanges,结合startWith实现初始显示全部选项的效果。 - 唯一模板引用变量:通过
#auto{{i}}为每个Autocomplete生成唯一的引用,避免多个实例冲突。 - 异步管道优化:模板中使用
async管道自动处理Observable的订阅与销毁,避免内存泄漏。 - 模块化控件创建:封装
createServiceControl方法统一生成FormControl,保证动态添加的控件结构一致。
内容的提问来源于stack exchange,提问作者Daner
相关产品推荐
相关产品推荐

