Angular克隆表单无法提交数据,仅原始表单可正常提交
解决Angular动态克隆表单无法提交的问题
嘿,我看你遇到了Angular动态表单提交的麻烦——根据债务人数量克隆出来的表单没法提交数据,只有原始表单能正常工作对吧?这问题的核心原因很明确:你用jQuery直接克隆DOM元素,但这些克隆出来的表单控件根本没和Angular的响应式表单系统绑定,Angular完全“看不见”它们,提交自然只会读取原始表单的数据。
而且在Angular项目里直接用jQuery操作DOM也不符合它的设计理念,咱们应该用Angular自带的FormArray来实现动态添加表单的需求,这才是正确的打开方式。下面是具体的解决方案:
第一步:重构TS代码,改用FormArray管理动态表单
首先把原来的单个FormGroup改成包含FormArray的表单结构,这样就能动态添加多个债务人表单了:
import { Component, OnInit } from "@angular/core"; import { FormGroup, FormBuilder, Validators, FormArray } from "@angular/forms"; import { HttpClient } from "@angular/common/http"; import { Router } from "@angular/router"; @Component({ selector: "app-annex", templateUrl: "./annex.component.html", styleUrls: ["./annex.component.css"], }) export class AnnexComponent implements OnInit { annexForm: FormGroup; decreaseDebtor: number; alert: boolean = false; alertUnsuccesful: boolean = false; constructor( public fb: FormBuilder, private http: HttpClient, private router: Router ) { // 初始化主表单,包含一个用于存储债务人的FormArray this.annexForm = this.fb.group({ debtors: this.fb.array([]) }); } // 便捷获取debtors FormArray的方法 get debtorsFormArray(): FormArray { return this.annexForm.get('debtors') as FormArray; } // 创建单个债务人的表单组 createDebtorForm(): FormGroup { return this.fb.group({ debtor_name: ["", Validators.required], debtor_contact_person: ["", Validators.required], debtor_function: ["", Validators.required], debtor_address: ["", Validators.required], debtor_email: ["", [Validators.required, Validators.email]], debtor_phone_number: ["", Validators.required], debtor_proposed_limit: ["", Validators.required], debtor_invoice_term: ["", Validators.required], debtor_projected_turnover: ["", Validators.required], debtor_ledger: [null, Validators.required], client: [localStorage.getItem("id"), Validators.required] }); } // 处理文件上传,新增索引参数定位到对应债务人表单 uploadLedgerFile(event: { target: HTMLInputElement }, index: number) { const file = (event.target as HTMLInputElement).files[0]; this.debtorsFormArray.at(index).patchValue({ debtor_ledger: file }); this.debtorsFormArray.at(index).get("debtor_ledger")?.updateValueAndValidity(); } submitAnnexForm() { console.log(this.annexForm.value); if (this.annexForm.invalid) return; // 遍历所有债务人表单,构建FormData提交 this.debtorsFormArray.controls.forEach((debtorForm, index) => { const formData = new FormData(); Object.keys(debtorForm.value).forEach(key => { formData.append(key, debtorForm.value[key]); }); this.http.post<{ id: string }>("http://127.0.0.1:8000/api/annex/", formData) .subscribe( (result) => console.log(`第${index+1}个债务人提交成功:`, result), (error) => { console.error(`第${index+1}个债务人提交失败:`, error); this.alertUnsuccesful = true; } ); }); } ngOnInit() { const clientId = localStorage.getItem("id"); this.http.get<any>(`http://127.0.0.1:8000/api/create-client/${clientId}/`) .subscribe( (res) => { this.decreaseDebtor = res.debtors_included; // 根据债务人数量,动态添加对应数量的表单组到FormArray for (let i = 0; i < this.decreaseDebtor; i++) { this.debtorsFormArray.push(this.createDebtorForm()); } }, (error) => console.log(error) ); } }
第二步:修改HTML模板,绑定FormArray渲染动态表单
现在把HTML改成用Angular的指令循环渲染FormArray里的表单,彻底抛弃jQuery克隆DOM的方式:
<div id="myDiv"> <form [formGroup]="annexForm" (ngSubmit)="submitAnnexForm()"> <!-- 循环渲染每个债务人的表单 --> <table class="table" *ngFor="let debtor of debtorsFormArray.controls; let i = index" [formGroupName]="i"> <tbody class="annex-body"> <tr> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_name" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_contact_person" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_function" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_address" required /> </td> <td class="table-input-data"> <input class="my-input" type="email" formControlName="debtor_email" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_phone_number" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_proposed_limit" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_invoice_term" required /> </td> <td class="table-input-data"> <input class="my-input" type="text" formControlName="debtor_projected_turnover" required /> </td> <td class="table-input-data"> <input class="my-input" type="file" (change)="uploadLedgerFile($event, i)" required /> </td> </tr> </tbody> </table> <!-- 统一提交按钮,提交所有债务人数据 --> <button class="mybutton" type="submit">保存所有债务人信息</button> </form> </div>
为什么这样改能解决问题?
- 抛弃jQuery操作DOM:用Angular的
*ngFor和formGroupName指令动态渲染表单,所有控件都和Angular表单系统绑定,Angular能追踪每个表单的状态和值。 - FormArray管理动态表单:
debtorsFormArray相当于一个表单数组,每个元素都是一个独立的债务人表单组,提交时能获取到所有表单的数据。 - 文件上传适配:通过索引参数定位到对应的表单组,正确更新文件控件的值,确保每个债务人的文件都能被正确提交。
- 符合Angular设计理念:完全采用数据驱动的方式管理表单,避免了直接操作DOM带来的各种兼容性和状态同步问题。
这样修改后,所有生成的表单都会被Angular正确识别,提交时就能获取到全部债务人的数据啦!
内容的提问来源于stack exchange,提问作者KIPROTICH DOMINIC KORIR
相关产品推荐
相关产品推荐

