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

Angular基于FormArray实现动态表格表单的列遍历问题

Angular固定行列数字输入表单列动态遍历实现方案

表格表单预期效果

当前用FormArray承载行数据的实现思路完全合理,列无法动态遍历是模板写法错误导致的,不需要调整整体表单结构。

问题根因

  • 直接遍历row.controls不可行:FormGroup的controls是对象结构,不是有序数组,遍历后无法保证列顺序和定义顺序一致
  • 动态控件名绑定语法错误:formControlName="v{j}"是普通字符串写法,Angular不会解析括号内的变量,无法匹配到对应控件

修复实现

因为行列数都是固定预设值,直接基于列数生成索引数组遍历即可,逻辑完全可控。

TS部分调整

在组件内新增列索引数组供模板遍历,优化重复的FormArray获取逻辑:

// transport-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-transport-form',
  templateUrl: './transport-form.component.html'
})
export class TransportFormComponent implements OnInit {
  title = 'formarray';
  kostenForm!: FormGroup;
  nRows = 3;
  nColumns = 3;
  columnIndexes: number[] = [];

  constructor(private formBuilder: FormBuilder) {}

  get rows(): FormArray {
    return this.kostenForm.get('rows') as FormArray;
  }

  ngOnInit() {
    // 生成列索引序列
    this.columnIndexes = Array(this.nColumns).fill(0).map((_, i) => i);
    this.kostenForm = this.formBuilder.group({
      rows: this.formBuilder.array([])
    });
    // 初始化固定行数
    for (let i = 0; i < this.nRows; i++) {
      this.addRow();
    }
  }

  createRow(): FormGroup {
    const rowConfig: Record<string, string | [string, Validators[]]> = {};
    for (let j = 0; j < this.nColumns; j++) {
      // 数字输入可直接加正则校验,不需要额外指令
      rowConfig[`v${j}`] = ['', Validators.pattern(/^\d*\.?\d*$/)];
    }
    return this.formBuilder.group(rowConfig);
  }

  addRow(): void {
    this.rows.push(this.createRow());
  }
}

模板部分修复

替换硬编码的输入框,用[formControlName]属性绑定动态控件名,推荐用table标签实现表格结构更语义化:

<!-- transport-form.component.html -->
<div [formGroup]="kostenForm">
  <table border="1" cellpadding="8" cellspacing="0">
    <tbody formArrayName="rows">
      <tr *ngFor="let row of rows.controls; let rowIndex = index" [formGroupName]="rowIndex">
        <td *ngFor="let colIndex of columnIndexes">
          <input type="number" [formControlName]="'v' + colIndex" style="width: 80px;">
        </td>
      </tr>
    </tbody>
  </table>
</div>

<!-- 表单值调试 -->
<pre>{{ kostenForm.value | json }}</pre>

注意事项

  • 动态绑定表单控件名必须加方括号,写成[formControlName]="'v' + colIndex",Angular才会把引号内的内容作为表达式解析
  • 不要直接遍历FormGroup的controls对象,不同JS环境下对象key的遍历顺序可能存在差异,用预设的索引数组遍历能保证列顺序完全符合预期
  • 数字输入直接使用原生type="number"属性即可,配合响应式表单校验器就能实现输入限制,不需要自定义输入过滤指令

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 14:39:18