Build Angular form with two formarrays nested inside each other

50 views Asked by At

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>
0

There are 0 answers