V tomto článku nadviažem na predchádzajúci článok, ktorý sa venuje reaktívnym formulárom a dynamickému vytváraniu formulárov. Tentokrát som sa pohral s vnorenými formulármi, kde vo vnútri dvoch vnorených formulároch vytváram dynamický formulár.
Pri tvorbe dynamických formulárov je dôležité nezabudnúť, že je potrebné v HTML definovať formGroup, formGroupName a formArrayName. Angular totiž z toho vytvára Path a ak je zle nastavené vnáranie / štruktúra, tak zobrazí v konzole error. Pri poliach je dôležité uvádzať formControlName, inak sa nebudú aktualizovať hodnoty.
Kým pri klasických formulároch sú prvky formulára pomenované cez vlastnosti objektu, pri dynamických formulároch ide o pole a preto názov formulárového prvku je index v poli.
V nasledujúcich riadkoch uvádzam programový kód, kde demonštrujem reaktívny formulár s vnorenými formulármi a dynamicky vytvorenými prvkami formulára. Príklad je vytvorený pre Bootstrap a obsahuje aj základnú validáciu. Na príklade tak uvidíte viacero implementovaných techník, ktoré sa používajú vo formulároch.
V príklade nie je ukázaný spôsob nahratia Bootstrapu a podpory pre reaktívne formuláre. Toto je uvedené v predchádzajúcom článku, respektíve vo videu.
Obsah súboru component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
@Component({
selector: 'app-reactive-forms1',
templateUrl: './reactive-forms1.component.html',
styleUrls: ['./reactive-forms1.component.css']
})
export class ReactiveForms1Component implements OnInit {
form: FormGroup = new FormGroup({});
services: any;
serviceList: Array<any> = [
{ name: 'ADSL', code: 'ADSL', selected: false },
{ name: 'Cable Broad Band', code: 'CBL', selected: false },
{ name: 'Foxtel TV', code: 'FOXTEL', selected: true },
{ name: 'Home Wireless', code: 'HWL', selected: true },
{ name: '4G Network', code: '4G', selected: false }
];
createServiceList() {
const arr = this.serviceList.map(service => {
return this.fb.control(service.selected);
});
return { allServices: this.fb.array(arr) };
}
getSelectedServices() {
let result: any = [];
this.form.value.serviceInfo.servicesList.allServices.map((checked: boolean, index: number) => {
if (checked) {
result.push({ [(index + 1) + ""]: this.serviceList[index].name + ", " + this.serviceList[index].code });
}
})
return result;
}
constructor(private fb: FormBuilder) {
this.services = this.createServiceList();
}
ngOnInit(): void {
this.form = this.fb.group({
name: ['', Validators.required],
serviceInfo: this.fb.group({
deliveryDate: ['', Validators.required],
servicesList: this.fb.group(this.services)
})
});
}
get allServices(): FormArray {
let si: any = this.form.get("serviceInfo");
let sg: any = si.get("servicesList");
let as: FormArray = <FormArray>sg.get('allServices');
return as;
}
onSubmit() {
console.log(this.form.value);
console.log(this.getSelectedServices());
this.getSelectedServices().forEach((field: any) => {
console.log(field);
});
}
}
Obsah súboru component.html
<div class="container mt-4">
<h1>Select your services</h1>
<form [formGroup]="form" (submit)="onSubmit()">
<div class="form-group">
<label for="name">Your name:</label>
<input class="form-control" name="name" [formControlName]="'name'" />
</div>
<div class="mt-4" formGroupName="serviceInfo">
<div class="form-group">
<label>Delivery Date:</label>
<input
class="form-control"
[formControlName]="'deliveryDate'"
type="date"
/>
<div class="mt-4" formGroupName="servicesList">
<div class="form-group">
<div formArrayName="allServices">
<label>Services:</label>
<div *ngFor="let service of allServices.controls; let i = index">
<input
id="service_{{ i }}"
class="form-check-input"
[formControlName]="i"
[checked]="service.value"
type="checkbox"
value=""
/>
<span ngNonBindable> </span>
<label class="form-check-label" for="service_{{ i }}">
{{ serviceList[i].name }}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary" [disabled]="!form.valid">
Save
</button>
</div>
</form>
</div>
Záver
Dynamicky vytvorené controls sú typu Array a nie object. Preto ich názov je index namiesto názvu property v objekte. Keďže aktuálnych príkladov na túto problematiku je na internete málo, dúfam, že vám tento článok pomôže.