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
相关产品推荐
相关产品推荐

