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

动态添加MatInput后Material Autocomplete失效问题咨询

解决动态添加matInput后Autocomplete失效的问题

问题根源

你的代码存在三个核心问题:

  • 所有输入框共用同一个filteredOptions数组,监听的是整个serviceNames FormArray的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);
      });
    });
  }
}

关键修改点说明

  1. 独立过滤数据源:用filteredOptions数组存储每个输入框的过滤Observable,确保每个输入框的建议列表互不干扰。
  2. 单个控件监听:新增setupFilter方法,为每个FormControl单独监听valueChanges,结合startWith实现初始显示全部选项的效果。
  3. 唯一模板引用变量:通过#auto{{i}}为每个Autocomplete生成唯一的引用,避免多个实例冲突。
  4. 异步管道优化:模板中使用async管道自动处理Observable的订阅与销毁,避免内存泄漏。
  5. 模块化控件创建:封装createServiceControl方法统一生成FormControl,保证动态添加的控件结构一致。

内容的提问来源于stack exchange,提问作者Daner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:16:06