Angular 2 动态嵌套表单
Posted
技术标签:
【中文标题】Angular 2 动态嵌套表单【英文标题】:Angular 2 Dynamic Nested Form 【发布时间】:2016-10-23 15:19:13 【问题描述】:基本上我想创建一个带有嵌套对象的动态表单,如下图所示:
收益在模型上的数组中 我们应该能够根据需要添加/删除收益。 表单应同步底层表单控件和模型 支付次数是任意的,应从模型加载到表单中我没有找到关于如何在 Angular 2 中执行此操作的有效示例,尽管这在 Angular 1 中确实很容易做到。
以下是我最初的问题,我已对其进行了更新以进行澄清(见上文):
首先我只想指出,我知道几天前刚刚发布了新版本的 Angular 2 rc.2。因此,用于创建动态嵌套表单的代码可能已经更改了一些,但没有足够的文档来解决这个问题。
在 Angular 2 的最新版本中(我目前正在使用 rc.1,但计划更新到 rc.2)我需要创建一个这样的表单(视图的伪代码):
<form [ngFormModel]="form" (ngSubmit)="onSubmit()">
<input type="text" ngControl="name">
<div *ngFor="let expense for expenses; let i = index;" control-group="expenses">
<input type="text" ngControl="expense.amount" [(ngModel)]="myModel.expenses[i].amount">
<input type="checkbox" ngControl="expense.final" [(ngModel)]="myModel.expenses[i].final">
</div>
<a class="button" (click)="addExpenseControl()">Add</a>
<a class="button" (click)="deleteExpenseControl()">Delete</a>
</form>
所以上面的伪代码不起作用,但老实说,由于缺乏文档,我无法弄清楚如何连接这样的东西。有一些关于嵌套 ControlGroup 的教程,但这不适合这里的情况,因为我们需要能够动态添加和删除控制组,而且我需要能够将它们与模型同步。
我在这里找到了 Angular 团队提供的 plunkr,它允许向表单添加控件——但这不是添加/删除 ControlGroup,而是使用 ControlArray 而我不是确定这是否适用于这里?
我非常熟悉使用较新的基于模型的 Angular 2 表单,但是我正在寻找资源以便正确嵌套它们(动态地!),并将这些嵌套数据绑定到主表单模型中。我将如何引用视图中的嵌套控件?上面的伪代码是否更接近?我会从我的控制器发布代码,但老实说,当涉及到上面的嵌套费用(ControlGroup ??)时,我不知道从哪里开始......
【问题讨论】:
AControlGroup
与控件完全一样,我相信您可以以相同的方式添加它。
我也是这么想的,但即使是这样,问题仍然存在——我应该为ngControl=".."
和[(ngModel)]="..."
输入什么代码才能正确连接?
【参考方案1】:
我必须自己解决这个问题,因为 Angular 2 中的表单似乎仍在变化,而且我还没有看到任何其他类似的示例(尽管它似乎是一个非常常见的用例)。
Here is a plunkr 使用 Angular2 RC3 的工作示例。
我正在使用来自this document 的更新的 Angular 2 表单代码。
app.component.ts(包含表单):
import Component from '@angular/core';
import REACTIVE_FORM_DIRECTIVES, FormControl, FormGroup, FormArray from '@angular/forms';
@Component(
selector: 'my-app',
templateUrl: 'app/app.html',
directives: [REACTIVE_FORM_DIRECTIVES],
providers: []
)
export class AppComponent
form: FormGroup;
myModel:any;
constructor()
// initializing a model for the form to keep in sync with.
// usually you'd grab this from a backend API
this.myModel =
name: "Joanna Jedrzejczyk",
payOffs: [
amount: 111.11, date: "Jan 1, 2016", final: false,
amount: 222.22, date: "Jan 2, 2016", final: true
]
// initialize form with empty FormArray for payOffs
this.form = new FormGroup(
name: new FormControl(''),
payOffs: new FormArray([])
);
// now we manually use the model and push a FormGroup into the form's FormArray for each PayOff
this.myModel.payOffs.forEach(
(po) =>
this.form.controls.payOffs.push(this.createPayOffFormGroup(po))
);
createPayOffFormGroup(payOffObj)
console.log("payOffObj", payOffObj);
return new FormGroup(
amount: new FormControl(payOffObj.amount),
date: new FormControl(payOffObj.date),
final: new FormControl(payOffObj.final)
);
addPayOff(event)
event.preventDefault(); // ensure this button doesn't try to submit the form
var emptyPayOff = amount: null, date: null, final: false;
// add pay off to both the model and to form controls because I don't think Angular has any way to do this automagically yet
this.myModel.payOffs.push(emptyPayOff);
this.form.controls.payOffs.push(this.createPayOffFormGroup(emptyPayOff));
console.log("Added New Pay Off", this.form.controls.payOffs)
deletePayOff(index:number)
// delete payoff from both the model and the FormArray
this.myModel.payOffs.splice(index, 1);
this.form.controls.payOffs.removeAt(index);
请注意,上面我手动将新的 FormGroup 对象推送到 form.controls.payOffs 数组中,这是一个 FormArray 对象。
app.html(包含表单 html):
<form (ngSubmit)="onSubmit()" [formGroup]="form">
<label>Name</label>
<input type="text" formControlName="name" [(ngModel)]="myModel.name" placeholder="Name">
<p>Pay Offs</p>
<table class="simple-table">
<tr>
<th>Amount</th>
<th>Date</th>
<th>Final?</th>
<th></th>
</tr>
<tbody>
<tr *ngFor="let po of form.find('payOffs').controls; let i = index">
<td>
<input type="text" size=10 [formControl]="po.controls.amount" [(ngModel)]="myModel.payOffs[i].amount">
</td>
<td>
<input type="text" [formControl]="po.controls.date" [(ngModel)]="myModel.payOffs[i].date">
</td>
<td>
<input type="checkbox" [formControl]="po.controls.final" [(ngModel)]="myModel.payOffs[i].final">
</td>
<td>
<button (click)="deletePayOff(i)" style="color: white; background: rgba(255, 0, 0, .5)">x</button>
</td>
</tr>
</tbody>
<tr>
<td colspan="4" style="text-align: center; padding: .5em;">
<button (click)="addPayOff($event)" style="color: white; background: rgba(0, 150, 0, 1)">Add Pay Off</button>
</td>
</tr>
</table>
</form>
在 html 表单中,我使用如下语句将表单链接到输入上的模型:
... [formControl]="po.controls.amount" [(ngModel)]="myModel.payOffs[i].amount" ...
【讨论】:
我在 html 中使用了find
方法来查找控件,但是在.ts
的情况下,即controler side
angular2 无法找到控件并抛出错误cannot read property push of undefined
为什么?这是整个问题***.com/q/39349261/5043867,提前谢谢
@PardeepJain 如果您收到您提到的错误,那么这意味着您尝试调用push
的任何FormArray 在您的代码中的某个时刻都只是undefined
。我的猜测是 FormArray 还没有被创建,然后你试图将 FormGroup 推到“无”上。你得到这个工作了吗?你试过我的处理方法吗?我的方法使用 Model Driven 表单,因此我将 Angular 模型与数据以及表单对象保持同步。
对于仍在寻找有关该主题的好教程的人,我找到了这个(scotch.io/tutorials/…)希望这会有所帮助
出于好奇,如果您只想在有收益的情况下添加收益控制,会发生什么?那么动态创建的 payoffs 的 formArray 怎么推?
@wolfhoundjesse 此代码应该可以满足您的要求。如果您在构造函数中注意到我创建了一个名为 myModel 的模型,它用于在加载表单时填充表单。您可能会从 Web API 填充您的模型,然后在收到响应后运行相同的代码。加载此表单时,它已经填充了我指定的两条记录,因此它可以按预期工作以上是关于Angular 2 动态嵌套表单的主要内容,如果未能解决你的问题,请参考以下文章