Angular表单多输入项数据重复问题求助
Angular动态表单多输入项数据重复问题解决
问题根源
- 所有动态生成的输入项都绑定到同一个
FormGroup(addInvoiceForm)的name/count/price控件,导致所有输入框共享同一数据源,输入时互相覆盖,提交时只能获取到最后一次输入的值。 addData方法遍历items时,始终取this.addInvoiceF['name'].value这类全局控件的值,而非每个动态项自己的表单数据,最终所有项数据完全重复。
解决方案:使用FormArray管理动态表单组
Angular的FormArray是专门用来管理一系列动态表单控件/表单组的工具,能让每个输入项拥有独立的数据源,彻底解决数据重复问题。
1. 修改TypeScript代码
import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators, FormBuilder, FormArray } from '@angular/forms'; import { PagesService } from '../pages.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-new-invoice', templateUrl: './new-invoice.component.html', styleUrls: ['./new-invoice.component.css'] }) export class NewInvoiceComponent implements OnInit { addInvoiceForm!: FormGroup; // 获取表单数组 get itemsFormArray(): FormArray { return this.addInvoiceForm.get('items') as FormArray; } constructor( private formBuilder: FormBuilder, private pagesService: PagesService, private router: Router ) { window.addEventListener('beforeunload', () => { for (let key in localStorage) { if (key.includes('formRows')) { localStorage.removeItem(key); } } }); } ngOnInit(): void { // 初始化表单,包含一个FormArray,默认有一个表单组 this.addInvoiceForm = this.formBuilder.group({ items: this.formBuilder.array([this.createItemFormGroup()]) }); } // 创建单个项的表单组 private createItemFormGroup(): FormGroup { return this.formBuilder.group({ name: ['', Validators.required], count: ['', Validators.required], price: ['', Validators.required] }); } // 添加新的表单项 addForm() { this.itemsFormArray.push(this.createItemFormGroup()); } // 删除指定表单项 deleteForm(index: number) { if (this.itemsFormArray.length > 1) { // 至少保留一个项 this.itemsFormArray.removeAt(index); } } addData() { if (this.addInvoiceForm.invalid) { return; } // 直接获取FormArray的所有值,无需手动映射 const formRows = this.itemsFormArray.value; this.pagesService.setFormData(formRows); console.log(formRows); this.router.navigate(['/preview-invoice']); } }
2. 修改HTML模板
<form method="POST" [formGroup]="addInvoiceForm" (ngSubmit)="addData()"> <!-- 绑定FormArray --> <div class="formularz" *ngFor="let item of itemsFormArray.controls; let i = index" [formGroupName]="i"> <mat-form-field> <mat-label>Name</mat-label> <input type="text" matInput formControlName="name" maxlength="30" minlength="3" required> <mat-error *ngIf="itemsFormArray.controls[i].get('name')?.errors?.['required']">Name is required</mat-error> </mat-form-field> <mat-form-field> <mat-label>Count</mat-label> <input type="number" formControlName="count" matInput> </mat-form-field> <mat-form-field> <mat-label>Price</mat-label> <input type="number" matInput formControlName="price" required> <mat-error *ngIf="itemsFormArray.controls[i].get('price')?.errors?.['required']">Price is required</mat-error> </mat-form-field> <button mat-icon-button color="primary" class="delete" matTooltip="Remove item" (click)="deleteForm(i)"> <mat-icon>delete</mat-icon> </button> </div> <div class="add-new"> <button type="button" mat-icon-button color="primary" class="add" matTooltip="Add new item" (click)="addForm()"> <mat-icon>add</mat-icon> Add new item </button> </div> <div class="add"> <button mat-icon-button color="primary" class="myButton" id="add_data_button"> Submit </button> </div> </form>
关键改动说明
- 用
FormArray替代原来的items数组,每个动态项都是FormArray中的一个独立FormGroup,数据互不干扰。 - HTML中通过
formArrayName绑定数组,formGroupName绑定数组索引,确保每个输入框对应正确的表单控件。 - 表单验证改为针对当前索引的控件,避免全局控件的混淆。
addData方法直接获取FormArray的value,无需手动映射,数据准确且代码更简洁。
内容的提问来源于stack exchange,提问作者LasagneLover
相关产品推荐
相关产品推荐

