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

Angular 14多表单行下国家/州/城市联动下拉框onchange异常求助

Angular 14 多行表单三级联动独立解决方案

你遇到的问题核心是所有表单行共用了同一个全局变量(columnarray、columnval),导致切换任意一行的选项时,所有行的下拉数据都会同步更新。要解决这个问题,必须让每一行的联动数据(国家、州、城市的可选列表)独立存储,同时用FormArray管理多行表单的状态。


1. 定义行数据结构与表单数组

先创建接口存储每行的联动数据,再用FormArray管理多行表单状态:

import { FormBuilder, FormArray, FormGroup } from '@angular/forms';

// 定义单行表单的联动数据结构
interface FormRow {
  country: string;
  stateOptions: any[];
  state: string;
  cityOptions: any[];
  city: string;
}

// 组件类内部
formArray: FormArray;
rowData: FormRow[] = []; // 存储每行独立的联动数据,与formArray索引一一对应

constructor(private fb: FormBuilder, private FormService: FormService) {
  // 初始化第一行表单和数据
  this.formArray = this.fb.array([this.createFormRow()]);
  this.rowData.push({ country: '', stateOptions: [], state: '', cityOptions: [], city: '' });
}

// 创建单行表单组
createFormRow(): FormGroup {
  return this.fb.group({
    country: [''],
    state: [''],
    city: ['']
  });
}

// 添加新行
addFormRow() {
  this.formArray.push(this.createFormRow());
  this.rowData.push({ country: '', stateOptions: [], state: '', cityOptions: [], city: '' });
}

// 删除行(可选)
removeFormRow(index: number) {
  if (this.formArray.length > 1) {
    this.formArray.removeAt(index);
    this.rowData.splice(index, 1);
  }
}

2. 修改联动事件处理函数

国家切换加载州选项

onCountryChange(event: any, rowIndex: number) {
  const selectedCountry = event.target.value;
  this.rowData[rowIndex].country = selectedCountry;

  const request = { DynamicTableName: selectedCountry };
  this.FormService.GetColoumnNames(request).subscribe(details => {
    // 仅更新当前行的州选项
    this.rowData[rowIndex].stateOptions = details.data;
    // 清空当前行的州、城市选中值及城市选项
    this.formArray.at(rowIndex).get('state')?.setValue('');
    this.rowData[rowIndex].cityOptions = [];
    this.formArray.at(rowIndex).get('city')?.setValue('');
  });
}

州切换加载城市选项(修改你的getcity函数)

getcity(event: any, rowIndex: number) {
  const selectedState = event.target.value;
  this.rowData[rowIndex].state = selectedState;

  const icolumn = { DynamicTableName: selectedState };
  this.FormService.GetColoumnNames(icolumn).subscribe(details => {
    // 仅更新当前行的城市选项
    this.rowData[rowIndex].cityOptions = details.data;
    // 清空当前行的城市选中值
    this.formArray.at(rowIndex).get('city')?.setValue('');
  });
}

3. 模板渲染多行表单

在HTML中循环绑定表单数组与对应行的联动数据:

<form [formGroup]="formArray">
  <!-- 循环渲染每一行 -->
  <div *ngFor="let row of formArray.controls; let i = index" [formGroupName]="i">
    <!-- 国家下拉框 -->
    <select formControlName="country" (change)="onCountryChange($event, i)">
      <option value="">选择国家</option>
      <option *ngFor="let country of countryList" [value]="country.value">
        {{ country.label }}
      </option>
    </select>

    <!-- 州下拉框 -->
    <select formControlName="state" (change)="getcity($event, i)" [disabled]="!row.get('country')?.value">
      <option value="">选择州</option>
      <option *ngFor="let state of rowData[i].stateOptions" [value]="state.value">
        {{ state.label }}
      </option>
    </select>

    <!-- 城市下拉框 -->
    <select formControlName="city" [disabled]="!row.get('state')?.value">
      <option value="">选择城市</option>
      <option *ngFor="let city of rowData[i].cityOptions" [value]="city.value">
        {{ city.label }}
      </option>
    </select>

    <button type="button" (click)="removeFormRow(i)" [disabled]="formArray.length === 1">删除行</button>
  </div>

  <button type="button" (click)="addFormRow()">添加新行</button>
</form>

核心逻辑说明

  • 用FormArray管理多行表单,确保每行的表单状态独立;
  • rowData数组与formArray行索引一一对应,存储每行专属的联动选项列表,彻底避免全局变量导致的同步问题;
  • 所有联动事件都传入当前行索引,仅更新对应行的数据和表单控件值。

内容的提问来源于stack exchange,提问作者Varalakshmi A M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:57:43