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

Angular动态行mat-select绑定已有数据异常问题

解决Angular动态行mat-select绑定重复值的问题

你遇到的核心问题是动态生成的行共用了相同的formControlName,同时混合使用ngModel和响应式表单导致绑定冲突,所以所有下拉框会同步显示最后选中的值。下面给你一步步拆解解决方案:

问题根源

  1. 你在*ngFor循环里给所有mat-select都用了相同的formControlName="associatedLoan"和formControlName="lienPosition",这会让所有行的下拉框绑定到同一个表单控件,自然会同步更新。
  2. Angular中响应式表单(formControlName)和模板驱动表单(ngModel)不建议混合使用,这会导致控件状态混乱,也是重复值的诱因之一。

正确的解决方案:用FormArray处理动态行表单

1. 组件类中构建FormArray

首先在你的组件里,把表单改成包含FormArray的结构,每一行对应一个FormGroup,里面包含两个FormControl:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';

@Component({
  // 你的组件元数据
})
export class YourComponent implements OnInit {
  lienForm: FormGroup;
  lienPositionData: any[] = []; // 你的初始数据源
  loanDropDownMultiSelect: any[] = []; // 下拉选项数据
  yourLienPositionOptions: any[] = []; // 第二个下拉框的选项数据

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    // 初始化表单,包含一个FormArray
    this.lienForm = this.fb.group({
      lienRows: this.fb.array([])
    });

    // 根据已有数据源lienPositionData初始化FormArray
    this.initLienRows();
  }

  // 获取FormArray的快捷方式,方便模板调用
  get lienRows(): FormArray {
    return this.lienForm.get('lienRows') as FormArray;
  }

  // 初始化行数据到FormArray
  initLienRows(): void {
    this.lienPositionData.forEach(person => {
      this.lienRows.push(this.fb.group({
        associatedLoan: [person.id], // 绑定初始id
        lienPosition: [person.text] // 绑定初始text
      }));
    });
  }

  // 添加新行
  addLienRow(): void {
    this.lienRows.push(this.fb.group({
      associatedLoan: [null],
      lienPosition: [null]
    }));
    // 同步更新数据源(如果需要保持数据源和表单一致)
    this.lienPositionData.push({id: null, text: null});
  }

  // 删除行
  remove(index: number): void {
    this.lienRows.removeAt(index);
    this.lienPositionData.splice(index, 1);
  }
}

2. 修改模板代码

把原来的表格改成绑定FormArray的结构,确保每一行的表单控件都对应FormArray里的独立FormGroup:

<form [formGroup]="lienForm">
  <table formArrayName="lienRows">
    <tr *ngFor="let row of lienRows.controls; let i = index" [formGroupName]="i">
      <td>
        <mat-form-field appearance="legacy" floatLabel="never">
          <mat-select formControlName="associatedLoan" name="associatedLoan-{{i}}">
            <mat-option 
              *ngFor="let lnDDL of loanDropDownMultiSelect | searchDocs:{productName: searchLoan}" 
              [value]="lnDDL.id" 
              style="cursor: pointer; margin: 6px; height: 38px;font-size: 14px;">
              {{lnDDL.productName}}
            </mat-option>
          </mat-select>
        </mat-form-field>
      </td>
      <td>
        <mat-form-field appearance="legacy" class="inline-block">
          <mat-select formControlName="lienPosition" name="lienPosition-{{i}}" placeholder="Select">
            <!-- 补上第二个下拉框的选项数据 -->
            <mat-option *ngFor="let option of yourLienPositionOptions" [value]="option.value">{{option.label}}</mat-option>
          </mat-select>
        </mat-form-field>
      </td>
      <td>
        <span class="table-remove">
          <button type="button" class="collateral-detail-button-remove" (click)="remove(i)" mat-flat-button>Remove</button>
        </span>
      </td>
    </tr>
  </table>

  <!-- 添加新行按钮 -->
  <button type="button" (click)="addLienRow()" mat-flat-button>Add Row</button>
</form>

关键调整点

  • 用formArrayName="lienRows"绑定整个数组,每一行用[formGroupName]="i"绑定对应的FormGroup,确保每个行的控件都是独立的。
  • 移除了[(ngModel)],完全用响应式表单的formControlName来绑定值,避免冲突。
  • 给每个name属性加上索引后缀-{{i}},确保DOM元素的name唯一,符合表单规范。
  • 如果需要获取所有行的最新数据,直接从lienForm.value.lienRows读取即可,无需手动同步数据源。

这样修改后,每一行的下拉框都会独立绑定对应的数据,不会再出现所有下拉框显示同一个值的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:33:58