I am building Angular form with two formarrays nested inside each other. I have an API enpoint that expects a JSON file whose structure is defined from three custom types.
Here are these three custom types
type Response = {
label: string;
questions?: Question[];
}
type Question = {
label: string;
responses?: Response[];
}
type Scenario = {
title: string;
description: Question[];
}
And here's the JSON file structure with the data on it
{
"title": "Cool Services",
"description": [
{
"label": "Assistance ménagère. Nos produits ?",
"responses": [
{
"label": "Gaz domestique",
"questions": [
{
"label": "Quantité ?",
"responses": [
{
"label": "7Kg",
"questions": [
{
"label": "Livraison à domicile ?",
"responses": [
{
"label": "Oui",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Numéro de téléphone ?"
}
]
},
{
"label": "Non",
"questions": [
{
"label": "Numéro de téléphone ?"
}
]
}
]
}
]
},
{
"label": "13Kg",
"questions": [
{
"label": "Livraison à domicile ?",
"responses": [
{
"label": "Oui",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Numéro de téléphone ?"
}
]
},
{
"label": "Non",
"questions": [
{
"label": "Votre numéro de téléphone ?"
}
]
}
]
}
]
},
{
"label": "18 Kg",
"questions": [
{
"label": "Livraison à domicile ?",
"responses": [
{
"label": "Oui",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Votre numéro de téléphone ?"
}
]
},
{
"label": "Non",
"questions": [
{
"label": "Votre numéro de téléphone ?"
}
]
}
]
}
]
}
]
}
]
},
{
"label": "Marmites",
"questions": [
{
"label": "Catégorie ?",
"responses": [
{
"label": "Marmite chauffante",
"questions": [
{
"label": "Contenance ?",
"responses": [
{
"label": "3L",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Votre numéro de téléphone ?"
}
]
},
{
"label": "5L",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Votre numéro de téléphone ?"
}
]
}
]
}
]
},
{
"label": "Marmite ordinaire",
"questions": [
{
"label": "Contenance ?",
"responses": [
{
"label": "5L",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Votre numéro de téléphone ?"
}
]
},
{
"label": "10L",
"questions": [
{
"label": "Nom du quartier ?"
},
{
"label": "Votre numéro de téléphone ?"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
I wrote this code but I get an infinite loop. I still don't know how to build this form.
export class ScenarioFormComponent implements OnInit {
scenarioForm!: FormGroup;
questionsForm!: FormGroup;
responsesForm!: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.initScenarioForm();
}
initScenarioForm() {
this.scenarioForm = this.fb.group({
title: '',
description: this.initQuestionsForm()
});
}
// INIT QUESTIONS & RESPONSES
initQuestionsForm() {
this.questionsForm = this.fb.group({
questions: this.fb.array([this.questionForm()])
});
return this.questionsForm
}
initResponsesForm() {
this.responsesForm = this.fb.group({
responses: this.fb.array([this.responseForm()])
});
return this.responsesForm;
}
// QUESTIONS & RESPONSES FORM
questionForm() {
return this.fb.group({
label: '',
responses: this.fb.array([this.initResponsesForm()])
});
}
responseForm() {
return this.fb.group({
label: '',
questions: this.fb.array([this.initQuestionsForm()])
});
}
// GET QUESTIONS AND RESPONSES
getQuestions() {
return this.questionsForm.controls['questions'] as FormArray;
}
getResponses() {
return this.responsesForm.controls['responses'] as FormArray;
}
// ADD QUESTIONS & RESPONSES
onAddQuestions() {
return this.getQuestions().push(this.initQuestionsForm());
}
onAddResponses() {
return this.getResponses().push(this.initResponsesForm());
}
// DELETE QUESTIONS & RESPONSES
onDeleteQuestions(index: number) {
this.getQuestions().removeAt(index);
}
onDeleteResponses(index: number) {
this.getResponses().removeAt(index);
}
// SUBMIT SCENARIO FORM
onSubmit() {
}
}
Here is UI
<form [formGroup]="scenarioForm" (ngSubmit)="onSubmit()" >
<div>
<input type="text"
placeholder="Title"
formControlName="title"
>
</div>
<div formGroupName="description">
<div formArrayName="questions" *ngFor="let creds of getQuestions().controls; let i = index">
<ng-container [formGroupName]="i">
<div>
<input type="text"
placeholder="Label question"
formControlName="label"
>
</div>
<div formArrayName="responses" *ngFor="let cred of getResponses().controls; let j = index">
<ng-container [formGroupName]="j">
<div>
<input type="text"
placeholder="Label response"
formControlName="label"
>
</div>
<button type="button"
(click)="onDeleteResponses(j)">
Delete response
</button>
</ng-container>
</div>
<span (click)="onAddResponses(j)">Add response</span>
<button type="button"
(click)="onDeleteQuestions(i)">
Delete Question
</button>
</ng-container>
</div>
<span (click)="onAddQuestions(i)">Add question</span>
</div>
<div>
<button type="submit"
[disabled]="scenarioForm.invalid">
Submit
</button>
</div>
</form>