一般我們使用Angular處裡表單的問題,對於資料結構較為複雜的Model,我們都會採用Data Driven的方式,也就是使用Reactive Form,因為這樣對於資料結構複雜的Model來說是比較容易維護與掌控。
回到今天的主題,我們將介紹使用 Reactive Form動態產生表單欄位。因為我們平常工作可能多少會遇到需要動態產生表單欄位的需求。舉例來說,像是訂單的問題,它的資料結構可能像是這樣:
{OrderID:"A001",
Items:[
{ItemName:"橡皮擦",Price:15,Quantity:10},
{ItemName:"鉛筆",Price:10,Quantity:10},
{ItemName:"筆記本",Price:25,Quantity:25}
]}
如果我們新增一筆Item,就需要動態的產生Item的DOM。其實在Angular要完成動態產生表單欄位這樣的需求,不管資料結構有多複雜,大致只需要用到 FormGroup、 FormArray、FormControl、ngFor、 track by 就能搞定了 !!
這裡我們將用訂單的例子,來示範使用 Reactive Form來動態產生表單欄位
1. 首先,我們使用FormGroup、 FormArray與FormControl將表單建立起來。
2. 為了能夠動態產生Items,對於欄位Items我們使用FormArray。
3. 建立AddItem、CreateItem,用於新增欄位。
4. 使用ngFor來產生出Items的DOM。
5. 利用trackBy ,減少DOM 更新次數,提升效能。
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormArray } from '@angular/forms';
@Component({
selector: 'app-reactive-form-sample',
templateUrl: './reactive-form-sample.component.html',
styleUrls: ['./reactive-form-sample.component.css']
})
export class ReactiveFormSampleComponent implements OnInit {
Form: FormGroup;
FormContent: string;
Items: any;
constructor() { }
ngOnInit() {
this.InitForm();
}
InitForm(): void {
this.Form = new FormGroup({
OrderID: new FormControl(null),
Items: new FormArray([this.CreateItem()]),
});
}
AddItem(): void {
this.Items = this.Form.controls['Items'];
this.Items.push(this.CreateItem());
console.log(this.Items);
}
CreateItem(): FormGroup {
return new FormGroup({
ItemName: new FormControl(null),
Price: new FormControl(null),
Quantity: new FormControl(null)
});
}
OnSubmit() {
this.FormContent = JSON.stringify(this.Form.value);
}
TrackByFn(index, item): number {
console.log(index, item);
return index;
}
}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="w-50">
<form [formGroup]="this.Form" class="form-horizontal" (ngSubmit)="OnSubmit()" role="form">
<div class="form-row">
<div class="form-group col-sm-12">
<h5 style="display:inline">
<span class="badge badge-info col-sm-12 text-left">Order ID
<span style="color:crimson">*</span>
</span>
</h5>
<input formControlName="OrderID" class="form-control" type="text" />
</div>
</div>
<div formArrayName="Items" *ngFor="let item of this.Form.controls['Items'].value;trackBy: TrackByFn; let i = index;">
<div class="card" [formGroupName]="i">
<div class="card-header">
{{'Item['+i+']'}}
</div>
<div class="card-body">
<div class="form-row">
<div class="form-group col-sm-12">
<h5 style="display:inline">
<span class="badge badge-info col-sm-12 text-left">Item Name
<span style="color:crimson">*</span>
</span>
</h5>
<input formControlName="ItemName" class="form-control" type="text" />
</div>
</div>
<div class="form-row">
<div class="form-group col-sm-12">
<h5 style="display:inline">
<span class="badge badge-info col-sm-12 text-left">Price
<span style="color:crimson">*</span>
</span>
</h5>
<input formControlName="Price" class="form-control" type="number" />
</div>
</div>
<div class="form-row">
<div class="form-group col-sm-12">
<h5 style="display:inline">
<span class="badge badge-info col-sm-12 text-left">Quantity
<span style="color:crimson">*</span>
</span>
</h5>
<input formControlName="Quantity" class="form-control" type="number" />
</div>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-info col-sm-6" (click)="this.AddItem()">Add</button>
<button type="submit" class="btn btn-primary col-sm-6">Submit</button>
</form>
</div>
</div>
<br/>
<div *ngIf="this.FormContent!=null" class="row justify-content-center">
<div class="alert alert-warning" role="alert">
{{this.FormContent}}
</div>
</div>
</div>
完成後的範例如下:
留言
張貼留言