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

Angular动态表单行中select组件selectionChange仅触发当前行的实现问询

解决动态表单行中Mat-Select过滤相互干扰的问题

这个问题我之前也碰到过!核心原因是你所有的表单行都共用了同一个filteredcarPartsSub Observable和搜索控制组件,所以操作任何一行的下拉选择时,都会修改全局的数据源,导致其他行的选项跟着变化。要解决这个问题,我们需要给每一行表单创建独立的过滤控制和子类别数据源,让各行的状态互不影响。

具体修改步骤:

1. 调整表单结构,给每行添加独立的过滤控制和Observable

首先,我们需要让每个表单组(对应一行)都拥有自己的子类别搜索控制和过滤后的数据源。可以定义一个类型来规范表单组的结构,然后在新增行的时候初始化这些属性:

import { FormGroup, FormControl, FormArray, FormBuilder } from '@angular/forms';
import { BehaviorSubject } from 'rxjs';
import { startWith, map } from 'rxjs/operators';

// 定义表单行的类型,包含独立的过滤控制和子类别数据源
interface CarPartRow extends FormGroup {
  controls: {
    cat: FormControl;
    carPartSubCategory: FormControl;
    // 子类别搜索控制
    carPartsSubFilterCtrl: FormControl;
    // 子类别过滤后的数据源
    filteredCarPartsSub: BehaviorSubject<any[]>;
  };
}

// 假设你的表单数组是这样定义的
formArray = this.fb.array([]);

constructor(private fb: FormBuilder) {
  // 初始化第一行
  this.addNewRow();
}

// 新增表单行的方法
addNewRow() {
  const newRow = this.fb.group({
    cat: [],
    carPartSubCategory: [],
    carPartsSubFilterCtrl: new FormControl(''),
    filteredCarPartsSub: new BehaviorSubject<any[]>([])
  }) as CarPartRow;

  // 给子类别搜索添加过滤逻辑(如果需要搜索功能的话)
  newRow.controls.carPartsSubFilterCtrl.valueChanges.pipe(
    startWith(''),
    map(searchTerm => {
      const currentSubs = newRow.controls.filteredCarPartsSub.value;
      return currentSubs.filter(item => 
        item.name.toLowerCase().includes(searchTerm.toLowerCase())
      );
    })
  ).subscribe(filtered => {
    newRow.controls.filteredCarPartsSub.next(filtered);
  });

  this.formArray.push(newRow);
}

2. 修改子类别加载方法,针对当前行更新数据

原来的getCarPartsSubCategory方法会修改全局的filteredcarPartsSub,现在我们要改成根据传入的行索引,只更新当前行的数据源:

getCarPartsSubCategory(event: any, index: number) {
  const selectedCategory = event.value;
  const currentRow = this.formArray.at(index) as CarPartRow;

  if (selectedCategory?.carPartSubCategories) {
    // 将选中类别的子类别赋值给当前行的数据源
    currentRow.controls.filteredCarPartsSub.next([...selectedCategory.carPartSubCategories]);
    // 重置当前行的子类别选择框
    currentRow.controls.carPartSubCategory.setValue('');
  } else {
    // 如果没有选中类别,清空子类别选项
    currentRow.controls.filteredCarPartsSub.next([]);
  }
}

3. 更新HTML模板,绑定到当前行的独立属性

最后修改模板,让每个行的第二个Mat-Select绑定到当前行自己的搜索控制和过滤数据源:

<!-- 循环遍历表单数组,每行对应一个表单组 -->
<div *ngFor="let row of formArray.controls; let i = index" [formGroup]="row">
  <!-- 第一个分类选择框 -->
  <mat-select formControlName="cat" (selectionChange)="onChange($event); getCarPartsSubCategory($event, i)">
    <mat-option>
      <ngx-mat-select-search 
        [formControl]="row.controls.carPartsMultiFilterCtrl" 
        [placeholderLabel]="'search...'" 
        [noEntriesFoundLabel]="'not found'">
      </ngx-mat-select-search>
    </mat-option>
    <mat-option *ngFor="let item of filteredcarParts | async" [value]="item">
      {{ item.name }}
    </mat-option>
  </mat-select>

  <!-- 第二个子类别选择框 -->
  <mat-select formControlName="carPartSubCategory">
    <mat-option>
      <ngx-mat-select-search 
        [formControl]="row.controls.carPartsSubFilterCtrl" 
        [placeholderLabel]="'search...'" 
        [noEntriesFoundLabel]="'not found'">
      </ngx-mat-select-search>
    </mat-option>
    <mat-option *ngFor="let item of row.controls.filteredCarPartsSub | async" [value]="item">
      {{ item.name }}
    </mat-option>
  </mat-select>
</div>

<!-- 新增行按钮 -->
<button (click)="addNewRow()">添加新行</button>

关键原理说明:

现在每个表单行都拥有独立的filteredCarPartsSub BehaviorSubject和carPartsSubFilterCtrl,当你操作某一行的分类选择时,只会更新该行的子类别数据源,其他行的数据源不会被修改,自然就不会出现相互干扰的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 11:52:32