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

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);
  }
}

关键说明

  1. 动态过滤选项:getAvailableCities方法为每行下拉框生成专属可用列表,自动排除其他行已选的城市,同时保留当前行自身的选中值,保证用户切换选项时的流畅性。
  2. 删除恢复逻辑:删除行时,表单数组更新后,所有下拉框的可用列表会自动重新计算,被删除行的选中城市会回到其他下拉框的可选范围内。
  3. 边界处理:当只剩最后一行时禁用删除按钮,避免表单数组为空导致的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 21:25:16