3

Survey app checkbox photo

I currently faced the issue of building the form on multiple choice questions. At this moment, the form for single choice works well, only left multiple choice questions. The goal I want to have is something like this:

{
  "questions": [
    // if multiple choices question
    {
      "question_id": 17,
      "answer_ids": [81,82,83]
    },
    {
      "question_id": 20,
      "answer_ids": [101,102,104]
    }
  ]
}

survey.ts

    this.surveyForm = this.formBuilder.group({
      questions: formBuilder.array([])
    })

    for (var i = 0; i < this.questions.length; i++) {

      if(this.questions[i].question_type == '2') {
        // get multiple
        let question = formBuilder.group({
          question_id: [this.questions[i].id, Validators.required],
          answer_ids: formBuilder.array([])
        });
        this.surveyForm.controls['questions'].push(question);
        // for (var j = 0; j < this.questions[i].answers.length; j++) {
        //   console.log(j);
          // let answer = formBuilder.array(this.questions[i].answers)
          // console.log(answer)
          // this.questions[i].answers[j].push(new FormControl());
          // this.surveyForm.controls['questions'].controls['answer_ids'].push(new FormControl('', [Validators.required]))
        // };
        console.log('m')
      }
    }

survey.html

 <div *ngIf="surveyForm">
    <form [formGroup]="surveyForm">
      <div formArrayName="questions">
        <div *ngFor="let question of questions; let i = index" [formGroupName]="i" padding-bottom>
          <ion-row>
            <ion-col col-2>
              <h5>{{ i + 1 }}.</h5>
            </ion-col>
            <ion-col col-10>
              <h5>{{ question.text }}</h5>
              <p>{{ question.instruction }}</p>
              <div *ngIf="question.question_type == 1; else multiple_choice">
              <ng-template #multiple_choice>
                <ion-list formArrayName="answer_ids">
                  <div *ngFor="let choice of question.answers; let i = index">
                    <ion-item>
                      <ion-label style="white-space: normal;">{{ choice.id }}</ion-label>
                      <ion-checkbox (ionChange)="onChange(choice.id, $event._checked)" value="choice.id"></ion-checkbox>
                    </ion-item>
                  </div>
                </ion-list>
              </ng-template>
            </ion-col>
          </ion-row>
        </div>
      </div>
    </form>
  </div>

What could be the best way that I can get the value id from each multiple choice checkbox to push into the array of specific question?

Yewness
  • 322
  • 1
  • 4
  • 14
  • Something like this... https://stackoverflow.com/a/43424244/6294072 – AT82 Jun 01 '17 at 08:30
  • @AJT_82 Okay, it seems quite close to the structure. It seems like it has to refer to the question_id for different answer_ids. Somehow, I couldn't get push data with this code this.surveyForm.controls['questions'].controls['answer_ids'].push(new FormControl('' ", [Validators.required])) Am I doing it wrong? – Yewness Jun 01 '17 at 10:33
  • Could you create a plunker that I can tinker with? :) – AT82 Jun 01 '17 at 16:48
  • Haha, you just solved my issue before I get to see this. :P – Yewness Jun 02 '17 at 13:49
  • No problem. Yeah, I had some extra time yesterday, so I decided to do it myself :D Don't get spoiled now, this will probably not happen every time, haha. But great that it worked out, glad to hear I could help. Have a nice weekend and happy coding! :) – AT82 Jun 02 '17 at 13:51
  • Sure, guess the luck is on my side this time. I haven't used plunker, perhaps I should share this code so that others can use it for their project as well. Once again, thank you very much. :) – Yewness Jun 02 '17 at 13:57

1 Answers1

6

This question is very similar to this: Angular 2 how to get the multiple checkbox value?

But since your is a bit more nested, we need to dig a bit deeper into the change event of the checkboxes.

From the template, we need in the change event pass choice.id, $event.checked and i. Please notice the naming convention in your template for the index. You are using the same name i for both the top level iteration and the nested iteration, I have changed the nested iteration as j, so:

<div *ngFor="let choice of question.answers; let j = index">
  <ion-item>
    <ion-label style="white-space: normal;">{{ choice.id }}</ion-label>
    <ion-checkbox (ionChange)="onChange(choice.id, $event.checked, i)" value="choice.id">
    </ion-checkbox>
  </ion-item>
</div>

Please notice that in the change event we are passing i, the top level iteration, where we iterate the questions.

So and over to the change function. Here it's similar to the answer in above linked question, but we need to dig deeper, since what we need to reach is the inner formArray.

Change event would look like this, where the path to our inner formarray is monstrous, as can be seen per the value of answers below :)

onChange(id, isChecked, index) {
   // nested formarray, which is inside nested formgroup, inside outer array
   const answers = <FormArray>this.surveyForm.controls.questions.controls[index].controls.answer_ids

  if(isChecked) {
     answers.push(new FormControl(id))
  } else {
     let idx = answers.controls.findIndex(x => x.value == id)
     answers.removeAt(idx)
  }
}

This should do it! :)

Here's a DEMO!

AT82
  • 71,416
  • 24
  • 140
  • 167
  • 1
    Thanks! This is the solution I'm looking for. It works well between my single choice and multiple choices question. – Yewness Jun 02 '17 at 13:50