You need to enable JavaScript to run this app. 如何创建单元格带数值输入框的可变高度Angular表格并捕获输入数据
优惠活动
大模型
产品
解决方案
定价
更多

如何创建单元格带数值输入框的可变高度Angular表格并捕获输入数据

实现方案

核心思路

用Angular响应式表单的FormArray承载动态行数据,每个行对应一个FormGroup,行内每个月份对应一个FormControl,天然支持动态扩展、数据双向绑定和预填充。

步骤1:TS文件逻辑编写

首先导入所需依赖,定义表单结构、预填充逻辑和提交逻辑:

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

@Component({
  selector: 'app-table-form',
  templateUrl: './table-form.component.html'
})
export class TableFormComponent implements OnInit {
  // 表头月份数组
  months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
  // 特性项数组,可动态增删
  FigProfs = [
    {id: 1, nome: 'characteristic 1'},
    {id: 2, nome: 'characteristic 2'},
    {id: 3, nome: 'characteristic 3'}
  ];
  tableForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    // 初始化表单
    this.tableForm = this.fb.group({
      rows: this.fb.array([])
    });
    // 初始化行
    this.initRows();
    // 若需要从数据库预填充,调用这个方法即可
    // this.preFillData(从接口拿到的数据库数据);
  }

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

  // 初始化所有行的表单控件
  initRows(): void {
    this.FigProfs.forEach(row => {
      const rowGroup = this.fb.group({});
      // 每行添加所有月份的输入控件
      this.months.forEach(month => {
        rowGroup.addControl(month, new FormControl(null));
      });
      this.rowsFormArray.push(rowGroup);
    });
  }

  // 数据库数据预填充方法
  preFillData(dbData: any[]): void {
    dbData.forEach(item => {
      // 找到对应的行索引
      const rowIndex = this.FigProfs.findIndex(row => row.nome === item.characteristic);
      if (rowIndex > -1) {
        const rowGroup = this.rowsFormArray.at(rowIndex) as FormGroup;
        if (rowGroup.get(item.month)) {
          rowGroup.get(item.month).setValue(item.value);
        }
      }
    });
  }

  // 动态添加行方法
  addNewRow(newCharacteristic: {id: number, nome: string}): void {
    this.FigProfs.push(newCharacteristic);
    const newRowGroup = this.fb.group({});
    this.months.forEach(month => {
      newRowGroup.addControl(month, new FormControl(null));
    });
    this.rowsFormArray.push(newRowGroup);
  }

  // 提交逻辑
  submit(): void {
    const formValue = this.rowsFormArray.value;
    const result = {};
    // 格式化为你需要的 月份/特性名: 输入值 结构
    formValue.forEach((rowVal, index) => {
      const characteristicName = this.FigProfs[index].nome;
      Object.keys(rowVal).forEach(month => {
        result[`${month}/${characteristicName}`] = rowVal[month];
      });
    });
    // 这里拿到的result就是符合要求的格式,直接传给后端即可
    console.log(result);
  }
}

步骤2:HTML模板编写

对应替换原有模板:

<form [formGroup]="tableForm" (ngSubmit)="submit()" novalidate>
<table class="rtable">
    <tr>
        <th></th>
        <th *ngFor="let column of months">
            {{column}}
        </th>
    </tr>

    <tr formArrayName="rows" *ngFor="let rowGroup of rowsFormArray.controls; let rowIndex = index">
        <td>{{FigProfs[rowIndex].nome}}</td>
        <td [formGroup]="rowGroup" *ngFor="let column of months">
            <input type="number" [formControlName]="column" required class="formControl">
        </td>
    </tr>
</table>
<button class="btnsubmit" type="submit" [disabled]="tableForm.invalid">GO</button>
</form>

关键说明

  • 动态扩展行:直接调用TS中的addNewRow方法传入新的特性项即可,无需额外修改表单配置
  • 单元格位置识别:每个输入控件绑定的行索引+月份唯一对应单元格,提交时自动拼接为你需要的格式
  • 预填充:调用preFillData方法传入数据库返回的结构化数据即可自动填充到对应单元格,无需手动给每个输入框赋值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 13:09:03