bront
bront

Reputation: 48

angular 5 dynamic reactive forms

I am attempting to dynamically present users a set of questions for every product selected.

I have created the questions FormGroup, and then I iterate through the selected products and nest the group of questions beneath each product.

To a degree, this seems to work. The form is created, I can see it via the JSON pipe, and can interact with it.

The problem, however, is that all of the form controls for each product only update the controls for the last product (which I can see via {{form.value | JSON}}

Sample Code:

https://stackblitz.com/edit/angular-py4sam

app.component.ts

import { Component, NgModule, VERSION, OnInit } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormControl, FormGroup, FormArray, ReactiveFormsModule, Validators } from '@angular/forms';


@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
  questionsForm: FormGroup;
  qaForm: FormGroup;
  questions = [
    {
      'question': 'like?',
      'value': ''
    },
    {
      'question': 'own?',
      'value': ''
    }
  ]

  products = [
    {
      'make': 'fender'
    },
    {
      'make': 'gibson'
    }
  ]

  createQuestionsForm() {

    this.questionsForm = new FormGroup({
      questions: new FormArray([])
    });

    const qArray = <FormArray>this.questionsForm.controls['questions'];

    this.questions.forEach((item, index) => {
      const aGroup = new FormGroup({
          answer: new FormControl(item.question),
          value: new FormControl(item.value)
      })

      qArray.push(aGroup);

    })
  }

  ngOnInit() {

    this.createQuestionsForm();

    this.qaForm = new FormGroup(
      {
        qa: new FormArray([])
      });

    const qaFormArray = <FormArray>this.qaForm.controls['qa'];

    this.products.forEach((item, index) => {

      const fg = new FormGroup({
        make: new FormControl(item.make),
        form: this.questionsForm
      })

      qaFormArray.push(fg);

    })
  }
}

app.component.html

<h3>FORM</h3>

<form [formGroup]="qaForm">

    <div formArrayName='qa'>

        <div *ngFor="let prod of products; let productCount = index">

            <h3>{{ prod.make }}</h3>

            <div [formArrayName]=productCount>

                <div formGroupName="form">

                    <div formArrayName="questions">

                        <div *ngFor="let q of questions; let qCount = index">

                            <div [formArrayName]=qCount>

                                <input type="checkbox" formControlName="value"> {{ q.question }}

                            </div>

                        </div>

                    </div>

              </div>

        </div>

    </div>

</div>
</form>

<p>qaform {{ qaForm.value | json }}</p>

Upvotes: 1

Views: 530

Answers (1)

yurzui
yurzui

Reputation: 214315

The issue here is that you use the same questionsForm for all products:

const fg = new FormGroup({
  make: new FormControl(item.make),
  form: this.questionsForm
        ^^^^^^^^^^^^^^^
})

In order to fix it you need to create questionsForm per product.

Here is how it could be accomplish:

createQuestionsForm() {

  const questionsForm = new FormGroup({
    questions: new FormArray([])
  });

  const qArray = <FormArray>questionsForm.controls['questions'];

  this.questions.forEach((item, index) => {

    const aGroup = new FormGroup({
      answer: new FormControl(item.question),
      value: new FormControl(item.value)
    })

    qArray.push(aGroup);

  })

  return questionsForm;
}
...
this.products.forEach(
  ...
  const fg = new FormGroup({
    make: new FormControl(item.make),
    form: this.createQuestionsForm()
  })

Forked Stackblitz

Upvotes: 1

Related Questions