Angular 6中如何实现Mat表格内每行独立的Mat输入文本框验证?
Angular 6中如何实现Mat表格内每行独立的Mat输入文本框验证?
我完全理解你现在遇到的麻烦——在Mat表格里给每行加输入框时,所有行的输入内容和验证提示都同步了,这显然不是你想要的效果。你提到尝试过FormArray但没成功,那咱们一步步把这个问题解决掉。
问题根源
你之前的写法不管是用单个FormControl还是错误的FormArray用法,本质上都是让所有行共用了同一个表单控件,所以输入内容会串在一起,验证也会同时作用在所有行上。想要每行独立,必须给每一行分配一个专属的FormControl,然后用FormArray来管理这些控件。
正确实现步骤
1. 在TS文件中构建包含FormArray的表单
首先,我们要根据表格的数据源长度,为每行创建一个带验证规则的FormControl,然后把这些控件放进FormArray里,再包裹到一个FormGroup中。
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms'; // 导入你的数据源相关类型,比如: // import { YourDataType } from './your-data-type'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html', styleUrls: ['./your-component.component.css'] }) export class YourComponent implements OnInit { commentsForm: FormGroup; dataSource: any; // 替换成你的实际数据源(比如MatTableDataSource<YourDataType>) displayedColumns: string[] = ['cmts', /* 其他列名 */]; submitted = false; constructor(private fb: FormBuilder) {} ngOnInit(): void { // 初始化FormArray:为数据源的每一行创建一个带验证的FormControl this.initCommentsForm(); // 监听数据源变化,如果数据更新(比如分页、过滤),同步更新FormArray this.dataSource.connect().subscribe(data => { this.refreshCommentsForm(data); }); } // 初始化表单 private initCommentsForm(): void { const initialControls = this.dataSource.data.map(() => this.fb.control('', [ Validators.required, Validators.minLength(10), Validators.maxLength(40) ]) ); this.commentsForm = this.fb.group({ commentsArray: this.fb.array(initialControls) }); } // 数据源变化时刷新FormArray private refreshCommentsForm(data: any[]): void { const newControls = data.map(() => this.fb.control('', [ Validators.required, Validators.minLength(10), Validators.maxLength(40) ]) ); this.commentsArray.clear(); newControls.forEach(control => this.commentsArray.push(control)); } // 获取FormArray的快捷方法,方便模板调用 get commentsArray(): FormArray { return this.commentsForm.get('commentsArray') as FormArray; } // 表单提交处理 onSubmit(): void { this.submitted = true; // 如果表单无效,标记所有控件为已触摸,强制显示错误 if (this.commentsForm.invalid) { this.commentsArray.controls.forEach(control => control.markAsTouched()); return; } // 获取每行的评论值,和数据源结合 const comments = this.commentsArray.value; const dataWithComments = this.dataSource.data.map((item, index) => ({ ...item, cmnts: comments[index] })); // 这里可以把dataWithComments发送到后端,比如: // this.yourService.saveComments(dataWithComments).subscribe(...); } }
2. 修改HTML模板,绑定每行的专属控件
把表单包裹在表格外面,然后在matCellDef里通过rowIndex绑定到FormArray中对应的控件,这样每行的输入框就独立了。
<form [formGroup]="commentsForm"> <table mat-table [dataSource]="dataSource" class="" matSort> <!-- 其他列的定义(保留你原来的代码) --> <ng-container matColumnDef="cmts"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Comments </th> <td mat-cell *matCellDef="let element; let rowIndex = index"> <span *ngIf="element?.sts=='A'"> <mat-form-field> <input matInput [formControl]="commentsArray.at(rowIndex)" placeholder="Enter your comments" > <mat-error *ngIf="commentsArray.at(rowIndex).invalid && (commentsArray.at(rowIndex).touched || submitted)"> <span *ngIf="commentsArray.at(rowIndex).errors?.required">Comments are required</span> <span *ngIf="commentsArray.at(rowIndex).errors?.minlength">Minimum length should be 10 characters</span> <span *ngIf="commentsArray.at(rowIndex).errors?.maxlength">Maximum length should be 40 characters</span> </mat-error> </mat-form-field> </span> </td> </ng-container> <!-- 表格行渲染 --> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <!-- 提交按钮(根据你的需求添加) --> <button mat-raised-button color="primary" (click)="onSubmit()">Submit Comments</button> </form>
关键注意点
- 数据源同步:如果你的表格有分页、过滤或排序功能,一定要监听数据源的变化,同步更新FormArray的长度,否则会出现控件和行不匹配的情况。
- 验证触发:提交表单时,记得手动标记所有控件为
touched,这样即使用户没点击过输入框,也会显示错误提示。 - 控件独立性:通过
rowIndex绑定commentsArray.at(rowIndex),确保每行的输入框对应唯一的FormControl,这样输入和验证就不会互相影响了。
备注:内容来源于stack exchange,提问作者sai
相关产品推荐
相关产品推荐

