From data that I recive from API I want to create a reactive form. I have a formparent and multiple childforms. The data that I want to display in form looks like this:
data{
"extraInformation": false
"cars": [
{
"Id": 48,
"Period": {
"Start": null,
"End": null },
"Rentalstats": null,
"Reason": null
}
]
}
How do I achieve this? So far this is what I have done:
this.form = this.formBuilder.group({
extraInformation: [this.data.ExtraInformation, [Validators.required]],
cars: this.fb.array([this.addDetailFormGroup()]),
});
addDetailFormGroup() {
this.form = new FormGroup({
Reason: new FormControl(this.data?.cars?.Reason, Validators.required),
Rentalstats: new FormControl(this.data?.cars?.Rentalstats, Validators.required),
Period: new FormGroup([this.initListFormGroup()]),
});
initListFormGroup() {
return new FormGroup({
Start: new FormControl(this.data?.cars?.Period?.Start, Validators.required),
End: new FormControl(this.data?.cars?.Period?.End, Validators.required),
});
}
But it dosent work because I get "Cannot read properties of undefined (reading 'Start')..
I would really appreciate it if someone could help
Would say that your code is not compilable as there are a few errors:
You are trying to re-assign the FormGroup
instance with the form controls: Reason
, Rentalstats
, and Period
that overwrite the original FormGroup
with the form controls: extraInformation
and cars
array.
From the attached data, this.data?.cars
is an array, you can't directly access Reason
and other fields, but you need to iterate each element of the cars
array, create FormGroup
for each element and adding it into the cars
FormArray
.
Period: new FormGroup([this.initListFormGroup()]),
This is not the proper way to assign the FormGroup
instance to Period
FormGroup
. Your current code is trying to assign the value as FormGroup
to a FormGroup
control.
Incorrect way to declare initListFormGroup
method. You should declare the method outside of addDetailFormGroup
method.
The naming of the methods to create FormGroup
is unclear/not meaningful, you should name it something like initCarFormArray
and initPeriodFormGroup
for better readability.
The component code to create the form
and its nested FormArray
and `FormGroup(s) should look as below:
ngOnInit() {
this.form = this.formBuilder.group({
extraInformation: [this.data.extraInformation, [Validators.required]],
cars: this.formBuilder.array([]),
});
this.initCarFormArray();
}
initCarFormArray() {
for (let car of this.data.cars) {
let carFormGroup = this.formBuilder.group({
Reason: new FormControl(car?.Reason, Validators.required),
Rentalstats: new FormControl(car?.Rentalstats, Validators.required),
Period: this.initPeriodFormGroup(car.Period),
});
this.cars.push(carFormGroup);
}
}
initPeriodFormGroup(period: any) {
return new FormGroup({
Start: new FormControl(period?.Start, Validators.required),
End: new FormControl(period?.End, Validators.required),
});
}
get cars(): FormArray {
return this.form.controls.cars as FormArray;
}
For the HTML to generate the form
:
<div [formGroup]="form">
<div>
<span>ExtraInformation:</span>
<input formControlName="extraInformation" />
</div>
<div formArrayName="cars">
<ng-container *ngFor="let controls of cars.controls; let i = index;">
<div [formGroupName]="i">
<div formGroupName="Period">
<div>
<span>Start:</span>
<input formControlName="Start" />
</div>
<div>
<span>End:</span>
<input formControlName="End" />
</div>
</div>
<div>
<span>Rentalstats:</span>
<input formControlName="Rentalstats" />
</div>
<div>
<span>Reason:</span>
<input formControlName="Reason" />
</div>
</div>
</ng-container>
</div>
</div>