私はAngular 2の初心者であり、公式のAngularガイドを読むことが最良の学習方法であると判断しました。
Reactive Forms Guideを確認しました https://angular.io/guide/reactive-forms
デモリンク: https://stackblitz.com/angular/jammvmbrpxle
内容は全体的にかなり良いものでしたが、より複雑なフォームをどのように実装するかということに固執しています。与えられた例では、各ヒーローには多くのアドレスの可能性があります。アドレス自体はフラットオブジェクトです。
住所にある部屋の色やタイプなどの追加情報が住所にあった場合。
export class Address {
street = '';
city = '';
state = '';
Zip = '';
rooms = Room[];
}
export class Room {
type = '';
}
フォームモデルは次のようになります...
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
Zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})]),
})]),
power: '',
sidekick: ''
});
}
EDIT-ngOnChangesで機能するファイナライズされたコード
hero-detail.component.ts
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
Zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})
])
})
]),
power: '',
sidekick: ''
});
}
ngOnChanges() {
this.heroForm.reset({
name: this.hero.name,
});
this.setAddresses(this.hero.addresses);
}
setAddresses(addresses: Address[]) {
let control = this.fb.array([]);
addresses.forEach(x => {
control.Push(this.fb.group({
street: x.street,
city: x.city,
state: x.state,
Zip: x.Zip,
rooms: this.setRooms(x) }))
})
this.heroForm.setControl('secretLairs', control);
}
setRooms(x) {
let arr = new FormArray([])
x.rooms.forEach(y => {
arr.Push(this.fb.group({
type: y.type
}))
})
return arr;
}
hero-detail.component.html(ネストされたフォーム配列部分)
<div formArrayName="secretLairs" class="well well-lg">
<div *ngFor="let address of heroForm.get('secretLairs').controls; let i=index" [formGroupName]="i" >
<!-- The repeated address template -->
<h4>Address #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="Zip">
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
<div formArrayName="rooms" class="well well-lg">
<div *ngFor="let room of address.get('rooms').controls; let j=index" [formGroupName]="j" >
<h4>Room #{{j + 1}}</h4>
<div class="form-group">
<label class="center-block">Type:
<input class="form-control" formControlName="type">
</label>
</div>
</div>
</div>
</div>
<button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>
ネストされたformarrayを持つことはそれほど違いはありません。基本的に、ネストされた配列で...持っているコードを複製するだけです:)ここにサンプルがあります:
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
// you can also set initial formgroup inside if you like
companies: this.fb.array([])
})
}
addNewCompany() {
let control = <FormArray>this.myForm.controls.companies;
control.Push(
this.fb.group({
company: [''],
// nested form array, you could also add a form group initially
projects: this.fb.array([])
})
)
}
deleteCompany(index) {
let control = <FormArray>this.myForm.controls.companies;
control.removeAt(index)
}
これが最も外側のフォーム配列の追加と削除であるため、ネストされたフォーム配列へのフォームグループの追加と削除はコードを複製するだけです。テンプレートのどこから、新しいプロジェクトを追加(この場合)するか、またはプロジェクトを削除する配列に現在のフォームグループを渡します。
addNewProject(control) {
control.Push(
this.fb.group({
projectName: ['']
}))
}
deleteProject(control, index) {
control.removeAt(index)
}
テンプレートも同じ方法で、外側のformarrayを繰り返し、次に内側の内側のformarrayを繰り返します。
<form [formGroup]="myForm">
<div formArrayName="companies">
<div *ngFor="let comp of myForm.get('companies').controls; let i=index">
<h3>COMPANY {{i+1}}: </h3>
<div [formGroupName]="i">
<input formControlName="company" />
<button (click)="deleteCompany(i)">
Delete Company
</button>
<div formArrayName="projects">
<div *ngFor="let project of comp.get('projects').controls; let j=index">
<h4>PROJECT {{j+1}}</h4>
<div [formGroupName]="j">
<input formControlName="projectName" />
<button (click)="deleteProject(comp.controls.projects, j)">
Delete Project
</button>
</div>
</div>
<button (click)="addNewProject(comp.controls.projects)">
Add new Project
</button>
</div>
</div>
</div>
</div>
編集:
データを取得したらフォームに値を設定するには、次のメソッドを呼び出してデータを反復処理し、フォームに値を設定します。この場合、data
は次のようになります。
data = {
companies: [
{
company: "example comany",
projects: [
{
projectName: "example project",
}
]
}
]
}
setCompanies
を呼び出して、フォームに値を設定します。
setCompanies() {
let control = <FormArray>this.myForm.controls.companies;
this.data.companies.forEach(x => {
control.Push(this.fb.group({
company: x.company,
projects: this.setProjects(x) }))
})
}
setProjects(x) {
let arr = new FormArray([])
x.projects.forEach(y => {
arr.Push(this.fb.group({
projectName: y.projectName
}))
})
return arr;
}