Search code examples
jsonangularformbuilder

Angular: json to formBuilder to json


From my server I am receiving a json that contains questions and different options:

[
{"description":"what is a color","questionID":"1","options":[{"response":"blue","optionID":"1"},{"response":"red","optionID":"2"},{"response":"football","optionID":"3"}]},
{"description":"what is a sport","questionID":"2","options":[{"response":"working","optionID":"4"},{"response":"playing","optionID":"5"},{"response":"dad","optionID":"6"},{"response":"chess","optionID":"7"}]}
]

With the formbuilder I created a form for this:

enter image description here

If I press submit I would like to send this json to my server:

{
"answers": [{"questionID":"1", "selectedoptionIDS":[{"selectedOptionID":"2"}]},
{"questionID":"2", "selectedoptionIDS":[{"selectedOptionID":"1"},{"selectedOptionID":"3"}]}
],
"email": "test@test.com"
}

I know how I can build my form with the formbuilder but when I press submit I am having troubles with responding the right JSON. Certainly because I can not work with this checkboxes. Can somebody help me with this?

Html page

  <form [formGroup]="examForm" (ngSubmit)="onSubmit(examForm.value)">
    <div formArrayName="answers">
      <div *ngFor="let question of questions; let i=index">
        <label>{{i+1}}) {{question.description}}</label>
        <br />
        <div *ngFor="let response of question.options">
          <input type="checkbox" value="response.optionID" />
          {{response.response}}
        </div>
      </div>
    </div>
    <label>Email:</label>
    <input class="form-control" id="email" type="text" formControlName="email">
    <div class="block-content block-content-full block-content-sm bg-body-light font-size-sm">
      <button class="btn btn-primary" type="submit">Submit</button>
    </div>
  </form>

TS Page

import { Component, OnInit } from '@angular/core';
import { ExamSimulatorService } from '../services/exam-simulator.service';
import { ActivatedRoute } from '@angular/router';
import { FormBuilder, FormArray } from '@angular/forms';

@Component({
  selector: 'app-exam',
  templateUrl: './exam.component.html'
})
export class ExamComponent implements OnInit {

  software;
  questions;
  examForm;


  constructor(
    private examSimulatorService: ExamSimulatorService,
    private formBuilder: FormBuilder
  ) {
    this.examForm = this.formBuilder.group({
      email: "",
      answers: this.formBuilder.array([
        this.initAnswer()])
    })


  }
  buildForm() {
    for (var i = 0; i < this.questions.length() + 1; i++) {
      this.addAnswer();
    }
  }
  initAnswer() {
    return this.formBuilder.group({
      questionID: "",
      selectedOptionIDs: this.formBuilder.array([
        this.initOptions()
      ])
    })
  }
  initOptions() {
    return this.formBuilder.group({
      selectedOptionID: ""
    })
  }
  addAnswer() {
    const answers = <FormArray>this.examForm["controls"]["answers"];
    answers.push(this.initAnswer())
    console.log(this.examForm);
  }

  addOption(i) {
    const options = <FormArray>this.examForm["controls"]["answers"]["controls"][i]["controls"]["selectedOptionIDs"]
    options.push(this.initOptions())
  }

  ngOnInit() {
    this.activatedRoute.paramMap
      .subscribe(params => {
        this.software = params['params']['software'];
        this.examSimulatorService.getExam(this.software).subscribe(response =>
          this.questions = response["questions"]["questionList"]);

      })
    setTimeout(() => this.buildForm(), 200)


  }
  onSubmit(values) {
    //this.examSimulatorService.addQuestion(values).subscribe(
    //  (responses) => {
    //    console.log(responses);
    //  });
    //this.options.clear();
    console.log(values);
  }

}

Solution

  • Instead of using your own model you can use full help from the Reactive form. The final model is not exactly you required but you can make workaround from it. You can see the working example at here https://stackblitz.com/edit/angular-1gtfmf

    Component

    export class ExamComponent implements OnInit {
      @Input() name: string;
      questionsList;
      examForm: FormGroup;
      dataModel: any; //active model
    
      constructor(
        private examSimulatorService: QuestionService,
        private formBuilder: FormBuilder
      ) { }
    
      get question(): FormGroup {
        return this.formBuilder.group(
          {
            questionID: "",
            description: "",
            options: this.formBuilder.array([])
          }
        );
      }
    
      get option(): FormGroup {
        return this.formBuilder.group({
          optionID: "",
          response: "",
          selected: false
        });
      }
    
      ngOnInit() {
    
        this.dataModel = Object.create(null);
    
        this.examForm = this.formBuilder.group({
          email: ['', [Validators.required]],
          questions: this.formBuilder.array([])
        });
    
        this.examSimulatorService.getAllQuestion().subscribe(response => {
          this.questionsList = response.data;
          this.loadForm(this.questionsList);
          console.log(this.questionsList);
        });
    
        this.examForm.valueChanges.subscribe(data => {
          this.dataModel = data;
        });
      }
    
      loadForm(data) {
    
        for (let ques = 0; ques < data.length; ques++) {
          const questionsFormArray = this.examForm.get("questions") as FormArray;
          questionsFormArray.push(this.question);
    
          for (let opt = 0; opt < data[ques].options.length; opt++) {
            const optionsFormsArray = questionsFormArray.at(ques).get("options") as FormArray;
            optionsFormsArray.push(this.option);
          }
        }
    
        this.examForm.controls.questions.patchValue(data);
      }
    
      showSavedValue() {
        return this.dataModel;
      }
    
      showValue() {
        return this.examForm.getRawValue();
      }
    
      onSubmit(values) {
        console.log(values);
      }
    
    
    }
    

    Html

    <form [formGroup]="examForm" (ngSubmit)="onSubmit(examForm.value)">
    
        <div>
            <label>Email:</label>
            <input class="form-control" id="email" type="text" formControlName="email">
        </div>
    
        <div formArrayName="questions">
            <div *ngFor="let question of examForm.get('questions').controls;let questionIndex=index" [formGroupName]="questionIndex">
                <label>{{questionIndex+1}} </label> {{examForm.value.questions[questionIndex].description}}
                <div formArrayName="options">
                    <div *ngFor="let option of question.get('options').controls; let optionIndex=index" [formGroupName]="optionIndex">
                        <input type="checkbox" formControlName="selected" value="" /> {{examForm.value.questions[questionIndex].options[optionIndex].response}}
                    </div>
                </div>
            </div>
    
            <div class="block-content block-content-full block-content-sm bg-body-light font-size-sm">
                <button class="btn btn-primary" type="submit">Submit</button>
            </div>
        </div>
    </form>
    
    <pre>  {{showSavedValue() | json }}
    
    <pre>{{showValue() | json}}</pre>