如何为Material Table自定义列的输入框添加FormArray
解决方案
1. 组件端配置表单结构
首先确保你的模块导入了ReactiveFormsModule,然后在组件类中初始化FormArray,用来管理每条未支付记录的支付金额输入:
import { FormBuilder, FormArray, FormGroup, Validators } from '@angular/forms'; // 组件类内部 paymentFormArray: FormArray; constructor(private fb: FormBuilder) { // 初始化空表单数组 this.paymentFormArray = this.fb.array([]); } // 当数据源加载/切换到未支付过滤器时,填充表单数组 initPaymentForms(unpaidShipments: any[]) { // 清空原有表单避免重复 this.paymentFormArray.clear(); // 为每条未支付记录创建独立FormGroup unpaidShipments.forEach(shipment => { this.paymentFormArray.push(this.fb.group({ shipmentId: [shipment.id], // 关联记录ID,用于匹配数据源 paymentAmount: [null, [Validators.required, Validators.min(300)]] // 验证规则:必填、金额不低于300 })); }); }
2. 模板绑定表单控件
修改payment_amount列的模板,将输入框绑定到FormArray的对应控件,同时添加验证提示:
<!-- 在表格外层添加表单容器 --> <form [formGroup]="paymentFormArray"> <ng-container matColumnDef="payment_amount"> <th mat-header-cell mat-sort-header *matHeaderCellDef> Payment Amount</th> <td mat-cell *matCellDef="let shipment; let index = index" [formGroupName]="index"> <mat-form-field> <mat-label>Payment Amount</mat-label> <mat-icon inline matPrefix fontIcon="attach_money"></mat-icon> <input matInput formControlName="paymentAmount" (blur)="calculateBill(index)" > <!-- 验证错误提示 --> <mat-error *ngIf="paymentFormArray.at(index).get('paymentAmount')?.hasError('required')"> 支付金额为必填项 </mat-error> <mat-error *ngIf="paymentFormArray.at(index).get('paymentAmount')?.hasError('min')"> 支付金额不能低于300 </mat-error> </mat-form-field> </td> </ng-container> <!-- 其他列保持原有逻辑不变 --> <ng-container matColumnDef="shipments.rate"> <th mat-header-cell mat-sort-header *matHeaderCellDef> Rate</th> <td mat-cell *matCellDef="let shipment"> {{shipment.rate | currency}}</td> </ng-container> <ng-container matColumnDef="shipments.fuel_surcharge"> <th mat-header-cell mat-sort-header *matHeaderCellDef> Fuel Surcharge</th> <td mat-cell *matCellDef="let shipment"> {{shipment.fuel_surcharge | currency}}</td> </ng-container> </form>
3. 修正计算逻辑
修改calculateBill方法,从FormArray中获取验证后的合法值,再匹配对应数据源记录更新:
calculateBill(index: number) { const formGroup = this.paymentFormArray.at(index) as FormGroup; // 表单无效时直接返回,避免非法计算 if (!formGroup.valid) return; const shipmentId = formGroup.get('shipmentId')?.value; const paymentAmount = formGroup.get('paymentAmount')?.value; // 找到数据源中对应的记录 const shipmentIndex = this.dataSource.shipmentsResponse.data.findIndex( shipment => shipment.id === shipmentId ); if (shipmentIndex !== -1) { // 更新rate和fuel_surcharge字段 this.dataSource.shipmentsResponse.data[shipmentIndex].rate = 300; this.dataSource.shipmentsResponse.data[shipmentIndex].fuel_surcharge = paymentAmount - 300; // 通知表格数据更新 this.dataSource._updateChangeSubscription(); } }
4. 同步表单与数据源
当过滤器切换到未支付状态时,调用initPaymentForms方法,传入未支付记录列表,确保FormArray与表格数据同步:
// 假设你的未支付过滤器触发方法为filterUnpaid() filterUnpaid() { const unpaidShipments = this.dataSource.shipmentsResponse.data.filter( shipment => shipment.status === 'unpaid' ); // 这里添加你原有更新表格数据源的逻辑 // ... // 初始化表单数组 this.initPaymentForms(unpaidShipments); }
关键说明
- 每个
FormGroup对应一条未支付记录,通过shipmentId关联数据源,避免索引错位问题 - 表单验证直接绑定到控件,无需手动处理输入合法性
- 利用
FormArray的原生API管理动态表单,符合Angular响应式表单规范
内容的提问来源于stack exchange,提问作者ctilley79
相关产品推荐
相关产品推荐

