如何创建单元格带数值输入框的可变高度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
相关产品推荐
相关产品推荐

