Angular 12响应式表单数组实现PrimeNg下拉框动态去重
实现方案
核心思路是基于表单数组的当前选中值,为每个下拉框动态生成过滤后的选项列表,不直接修改原始城市数据,确保删除行时能自动恢复选项:
- 保留原始城市列表作为数据源,不直接修改
- 为每个下拉框计算可用选项:排除其他所有已选中的城市
type(当前行自身的选中值不排除,避免切换时瞬间无选项) - 删除行时,移除对应行的选中值,其他下拉框的可用选项会自动更新
修改后的 app.component.html
<form [formGroup]="form"> <div> <div formArrayName="credentials" *ngFor="let creds of addDynamicRow?.controls; let i = index" > <div [formGroupName]="i" style="display: flex; gap: 10px; align-items: center;"> <p-dropdown [options]="getAvailableCities(i)" placeholder="Select a City" optionLabel="name" optionValue="type" formControlName="filterSelection" ></p-dropdown> <!-- 每行单独设置删除按钮 --> <button (click)="deleteCreds(i)" [disabled]="addDynamicRow.length === 1">Delete</button> </div> </div> </div> <br> <button (click)="addCreds()">Add</button> </form>
修改后的 app.component.ts
import { Component } from '@angular/core'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; interface City { id: number; name: string; key: string; type: string; } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { cities!: City[]; form!: FormGroup; constructor(private fb: FormBuilder) { this.form = this.fb.group({ credentials: this.fb.array([this.filterItemRow()]), }); // 原始城市数据源,始终保留不修改 this.cities = [ { id: 20, name: 'abc', key: 'abc', type: 'abc' }, { id: 11, name: 'def', key: 'def', type: 'def' }, { id: 1, name: 'ghi', key: 'ghi', type: 'ghi' }, { id: 2, name: 'jkl', key: 'jkl', type: 'jkl' }, { id: 3, name: 'mno', key: 'mno', type: 'mno' }, { id: 8, name: 'pqr', key: 'pqr', type: 'pqr' }, { id: 9, name: 'stu', key: 'stu', type: 'stu' }, { id: 10, name: 'vwx', key: 'vwx', type: 'vwx' }, { id: 17, name: 'yza', key: 'yza', type: 'yza' }, { id: 14, name: 'Days Down', key: 'daysDown', type: 'daysdown' }, ]; } // 获取表单数组实例 get addDynamicRow(): FormArray { return this.form.get('credentials') as FormArray; } // 创建单行表单组 filterItemRow() { return this.fb.group({ filterSelection: ['', Validators.required], }); } // 添加新行 addCreds() { const creds = this.addDynamicRow; creds.push(this.filterItemRow()); } // 计算指定行的可用城市列表 getAvailableCities(currentIndex: number): City[] { // 收集其他行已选中的type值 const selectedTypes = this.addDynamicRow.controls .map((control, index) => index !== currentIndex ? control.get('filterSelection')?.value : null) .filter(Boolean); // 返回未被其他行选中的城市,同时保留当前行已选城市(避免切换选项时无值可选) return this.cities.filter(city => !selectedTypes.includes(city.type) || city.type === this.addDynamicRow.at(currentIndex).get('filterSelection')?.value ); } // 删除指定行 deleteCreds(index: number) { const creds = this.addDynamicRow; creds.removeAt(index); } }
关键说明
- 动态过滤选项:
getAvailableCities方法为每行下拉框生成专属可用列表,自动排除其他行已选的城市,同时保留当前行自身的选中值,保证用户切换选项时的流畅性。 - 删除恢复逻辑:删除行时,表单数组更新后,所有下拉框的可用列表会自动重新计算,被删除行的选中城市会回到其他下拉框的可选范围内。
- 边界处理:当只剩最后一行时禁用删除按钮,避免表单数组为空导致的异常。
内容的提问来源于stack exchange,提问作者learner
相关产品推荐
相关产品推荐

