Angular响应式表单动态行Mat Table报错:this.validator is not a function
解决Angular响应式表单嵌套Mat Table时的
this.validator is not a function错误 看起来你遇到的问题根源在于表单初始化逻辑混乱,以及没有正确将Mat Table的数据与响应式表单的FormArray绑定起来。我来一步步帮你修正:
错误原因分析
- 你在构造函数里已经初始化了包含
actualsVolumeDataFormArray的formGroup,但在ngOnInit里又重新赋值了formGroup,直接覆盖了之前的表单结构,导致模板里的formArrayName="actualsVolumeData"找不到对应的FormArray控件,引发验证器相关错误。 - 你没有把初始的表格数据转换成FormGroup并添加到FormArray中,表单系统无法识别行数据的验证规则。
onAdd方法只修改了MatTableDataSource的数据,没有同步更新FormArray,导致表单和UI数据脱节。
修正后的完整代码
TypeScript部分
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms'; import { Router } from '@angular/router'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html', styleUrls: ['./your-component.component.css'] }) export class YourComponentComponent implements OnInit { columnsToDisplay: string[] = ['id', 'code', 'desc']; rows: FormArray = this.fb.array([]); formGroup: FormGroup = this.fb.group({ actualsVolumeData: this.rows }); constructor(private router: Router, private fb: FormBuilder) { } ngOnInit() { // 初始数据 const initialList = [ { code: 'one', desc: 'One1', id: 1 }, { code: 'two', desc: 'Two1', id: 2 }, { code: 'three', desc: 'Three1', id: 3 }, ]; // 将初始数据转换为FormGroup并添加到FormArray initialList.forEach(item => { this.rows.push(this.createRowForm(item)); }); } // 创建单行的FormGroup,添加验证规则 private createRowForm(item: any): FormGroup { return this.fb.group({ id: [item.id], // id设为不可编辑,直接绑定值 code: [item.code, Validators.required], desc: [item.desc, Validators.required] }); } onAdd() { // 添加新的空白行FormGroup const newRowId = this.rows.length + 1; this.rows.push(this.createRowForm({ id: newRowId, code: '', desc: '' })); } onSubmit() { if (this.formGroup.valid) { // 提交表单数据,this.formGroup.value就是完整的表单数据 console.log('提交的数据:', this.formGroup.value); // 这里添加你的提交逻辑 } } }
HTML部分
<form [formGroup]="formGroup"> <button mat-button (click)="onAdd()">Add New Row</button> <table mat-table [dataSource]="rows.controls" formArrayName="actualsVolumeData" class="mat-elevation-z8"> <!-- ID列 --> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef> ID </th> <td mat-cell *matCellDef="let row; let i = index" [formGroupName]="i"> {{ row.get('id')?.value }} </td> </ng-container> <!-- Code列(可编辑+验证) --> <ng-container matColumnDef="code"> <th mat-header-cell *matHeaderCellDef> Code </th> <td mat-cell *matCellDef="let row; let i = index" [formGroupName]="i"> <mat-form-field appearance="fill"> <input matInput formControlName="code" placeholder="Enter Code"> <mat-error *ngIf="row.get('code')?.invalid && row.get('code')?.touched"> Code is required </mat-error> </mat-form-field> </td> </ng-container> <!-- Description列(可编辑+验证) --> <ng-container matColumnDef="desc"> <th mat-header-cell *matHeaderCellDef> Description </th> <td mat-cell *matCellDef="let row; let i = index" [formGroupName]="i"> <mat-form-field appearance="fill"> <input matInput formControlName="desc" placeholder="Enter Description"> <mat-error *ngIf="row.get('desc')?.invalid && row.get('desc')?.touched"> Description is required </mat-error> </mat-form-field> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr> <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr> </table> <button mat-button [disabled]="!formGroup.valid" (click)="onSubmit()">Submit</button> </form>
关键修正点
- 表单结构稳定:不再覆盖
formGroup,始终保持actualsVolumeData作为FormArray的容器。 - 数据与表单绑定:用
createRowForm方法将每一行数据转换为带验证规则的FormGroup,添加到FormArray中,Mat Table的数据源直接绑定到rows.controls,确保UI和表单数据同步。 - 添加新行逻辑:
onAdd方法直接操作FormArray,添加新的FormGroup,UI会自动更新。 - 验证与提交:提交按钮根据表单整体状态禁用,确保只有验证通过才能提交,同时显示字段级的验证错误提示。
内容的提问来源于stack exchange,提问作者AkRoy
相关产品推荐
相关产品推荐

