You only need create an empty formArray in openingHours in the location
this.createAppForm = this.fb.group({
...
location: this.fb.group({
name: ['', Validators.required],
openingHours: this.fb.array([]), //<--this is an "empty" formAray
address: this.fb.group({
...
}),
}),
});
But (always there're a but) seeing your code you has many repetitions to create the differents FormGroups. And repeat code makes we enter in trouble early.
So we are going to create functions that return the formGroups that compouned your FormGroup
Imagine you has some like
setHeadLine(data: any = null) {
data = data || { language: null, headlineText: null };
return this.fb.group({
headlineText: data.headlineText,
language: data.language,
});
}
setBodyText(data: any = null) {
data = data || { bodyText: null, language: null };
return this.fb.group({
bodyText: data.bodyText,
language: data.language,
});
}
setAddress(data: any = null) {
data = data || { postCode: null, country: null };
return this.fb.group({
postCode: [data.postCode, Validators.required],
country: [data.country, Validators.required],
});
}
setOpeningHour(data: any = null) {
data = data || { day: null, timing: null };
return this.fb.group({
day: [data.day, Validators.required],
timing: [data.timing, Validators.required],
});
}
setLocation(data: any = null) {
console.log(data);
data = data || { name: null, openingHours: null, address: null };
return this.fb.group({
name: [data.name, Validators.required],
openingHours: this.fb.array(
data.openingHours
? data.openingHours.map((x) => this.setOpeningHour(x))
: []
),
address: this.setAddress(data.address),
});
}
See how the "setLocation" call to the function setAddress to create the formGroup adress and how openingHours is a this.fb.array. If data.openingHours is an array, convert the array of objects in an array of formGroups and create the formArray, else return an empty array
Finally you create a function that return your formGroup
setFormGroup(data: any = null) {
data = data || { headline: null, bodyText: null, location: null };
return this.fb.group({
headline: this.fb.array(
data.headline ? data.headline.map((x) => this.setHeadLine(x)) : []
),
bodyText: this.fb.array(
data.bodyText ? data.bodyText.map((x) => this.setBodyText(x)) : []
),
location: this.setLocation(data.location),
});
}
I this way you not repeat code. In the constructor you can write
this.createAppForm = this.setFormGroup(this.data);
And when you add a FormGroup simply call the functions:
addHeadline() {
this.getHeadlineFormData().push(this.setHeadLine())
}
addBodyText() {
this.getBodyTextFormData().push(this.setBodyText())
}
addOpeningHours() {
this.getopeningHoursFormData().push(this.setOpeningHour())
}
Well, (this last is only a suggestion) I think that the code becomes more clear using "getter", so if you replace
//replace
getHeadlineFormData() {
return <FormArray>this.createAppForm.get('headline');
}
//by
get headlineFormData() {
return <FormArray>this.createAppForm.get('headline');
}
//replace
getBodyTextFormData() {
return <FormArray>this.createAppForm.get('bodyText');
}
//by
get bodyTextFormData() {
return <FormArray>this.createAppForm.get('bodyText');
}
//replace
getLocationFormData() {
return <FormArray>this.createAppForm.get('location');
}
//by
get locationFormData() {
return <FormArray>this.createAppForm.get('location');
}
//and replace
getopeningHoursFormData() {
return <FormArray>this.createAppForm.get('location')?.get('openingHours');
}
//by
get openingHoursFormData() {
return <FormArray>this.createAppForm.get('location')?.get('openingHours');
}
You can use this.headlineFormData instead this.getHeadlineFormData() -see that using a getter you don't write parentesis. and in html headlineFormData.controls instead getHeadlineFormData().controls -again see that using a "getter" you don't write parenthesis.
Your forked stackbliz