0

I am making a site where I can create exams with multiple choice questions. I have a html page in which I can add questions to an exam.

A question consists out of the description of the question and multiple options. An option contains the response and a value to check if the response is true or false.

The user should be able to add options to the question when filling in the form. I am trying to use formbuilder, formgroup and formarray for this but it is not working. When I press add option, a new response and a new valid field should appear.

form

The fields are appearing on my html page, but I get this error when filling in the form. "Cannot find control with name response" +"cannot find control with name valid"

This is the HTML page:

    <form [formGroup]="questionForm" (ngSubmit)="onSubmit(questionForm.value)">
        <div>
          <label>Description:</label>
          <br />
          <input class="form-control" id="description" type="text" formControlName="description">
          <br />
          <label>Options</label>

          <div *ngFor="let test of arrayOptions; let i = index">
            <div class=mx-4>
              <label>Response</label>
              <input class="form-control" id="response" type="text" formControlName="response">
              <label>Valid</label>
              <input class="form-control" id="valid" type="text" formControlName="valid">
            </div>


          </div>

          <button type="button" class="btn-block-option text-primary" (click)="addOption()">
            <i class="fa fa-plus" aria-hidden="true"></i>Add option
          </button>


        </div>
        <div class="block-content block-content-full block-content-sm bg-body-light font-size-sm">
          <button class="btn btn-primary" type="submit">Add</button>
        </div>
      </form>

This is my ts page:

    export class AddQuestionComponent implements OnInit {

      questionForm;
      arrayOptions;

      constructor(
        private examSimulatorService: ExamSimulatorService,
        private formBuilder: FormBuilder
      ) {
        this.questionForm = this.formBuilder.group({
          description: '',
          options: ''
        })
      }
      removeOption(i) {
        this.questionForm.removeControl(i);
      }
      addOption() {

    this.questionForm.addControl(this.questionForm.controls.options.value, 
    this.formBuilder.array([this.formBuilder.group(
          {
            response: "",
            valid: ""
          }
        )]));
        this.arrayOptions.push(this.questionForm.controls.options.value);
      } 

      onSubmit(questionData) {
        this.examSimulatorService.addQuestion(questionData);
        this.questionForm.reset();
      }

      ngOnInit() {
        this.arrayOptions = [];
        this.addOption();
      }

    }

2 Answers 2

2

Hard to tell the exact errors without a running sample.

Some things I have noticed:

1) When we are using a FormArray we have to bind it in the template via formArrayName

2) I don't really get why you are calling addControl on the questionForm. Should'nt we push a new option to the FormArray?

Example form with a FormArray:

this.questionForm = this.fb.group({
  question: ["Sample Question"],
  options: this.fb.array([
    this.fb.group({
      response: ["Response Example"],
      valid: [true]
    })
  ])
});

Referencing the FormArray in the template via formArrayName:

<form [formGroup]="questionForm">
  <input type="text" formControlName="question" />

  <div formArrayName="options">

    <div *ngFor="let option of options.controls; let i=index">
      <b>Option {{i}}:</b>
      <div [formGroupName]="i">
          <input type="text" formControlName="response" />
          <input type="checkbox" formControlName="valid" />
      </div>
    </div>

</div>
</form>

Finally the method for adding a new option:

addOption() {
  this.options.push(
    this.fb.group({
      response: [""],
      valid: [false]
    })
  );
}

// getter which simplifies the access via 'this.options' used in the addOption method
get options() {
  return this.myForm.get("options") as FormArray;
}

Take a look at the codesandbox. Feel free to fork and edit it so that it shows your problem better.

Sign up to request clarification or add additional context in comments.

Comments

1

You didn't added formArray and formGroup in your html

HTML Code:

<form [formGroup]="questionForm" (ngSubmit)="onSubmit(questionForm.value)">
<div>
   <label>Description:</label>
   <br />
   <input class="form-control" id="description" type="text" formControlName="description">
   <br />
   <label>Options</label>
   <div formArrayName="options">
      <div *ngFor="let test of arrayOptions; let i = index">
         <div class=mx-4 [formGroupName]="i">
            <label>Response</label>
            <input class="form-control" id="response" type="text" formControlName="response">
            <label>Valid</label>
            <input class="form-control" id="valid" type="text" formControlName="valid">
         </div>
      </div>
   </div>
   <button type="button" class="btn-block-option text-primary" (click)="addOption()">
   <i class="fa fa-plus" aria-hidden="true"></i>Add option
   </button>
</div>
<div class="block-content block-content-full block-content-sm bg-body-light font-size-sm">
   <button class="btn btn-primary" type="submit">Add</button>
</div>
</form>

Component :

export class AppComponent implements OnInit {
  questionForm;
  arrayOptions;
  constructor(private formBuilder: FormBuilder) {
    this.questionForm = this.formBuilder.group({
      description: "",
      options: this.formBuilder.array([])
    });
  }

  ngOnInit() {
    this.arrayOptions = [];
    this.addOption();
  }

  removeOption(i) {
    this.questionForm.removeControl(i);
  }

  addOption() {
    const control = <FormArray>this.questionForm.get("options");
    const newGroup = this.formBuilder.group({
      response: "",
      valid: ""
    });
    control.push(newGroup);
    this.arrayOptions.push(this.questionForm.controls.options.value);
  }

  onSubmit(questionData) {
    console.log(questionData);
  }
}

Find the code here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.