girbic
girbic

Reputation: 321

Nested FormGroup generated dynamically. Need help to get this working

So I have a slightly unusual use case. To simplify, I'm getting a list of something we shall call "templates" from the backend. Each of these templates has a different number of template variables that go along with it (eg. one template might have 3 variables, another might have 2). A template along with user provided values for each template variable makes up a story.

So what I want to do is have a form that lets users create a story. Basically the form component will load a list of templates received from the backend. Now when they select a template from a dropdown list, I want to dynamically generate inputs for each of the variables. So far I have an input where the user enters a template name. I then generate a nested FormGroup on the fly that has a FormControl for each of the variables.

This is what I have so far: https://stackblitz.com/edit/angular-kt7rib

I am very close. For example, if you enter template1 into the input, it will generate two additional inputs for the variables for that template. However I get the following error message in the console: Error: Cannot find control with path: 'templateVariables -> variable1'. This is preventing me from getting the values from the top level FormGroup and sharing the validation logic from the child FormGroup.

I have an inkling that it's due to the fact that I'm dynamically generating the FormGroup, and so it doesn't get bound properly to the top level FormGroup.

How should I fix this? Thanks.

Upvotes: 0

Views: 101

Answers (1)

Eliseo
Eliseo

Reputation: 57929

it's only one deep?

In that case, for me, at first you defined your form like

this.form = this.fb.group({
  templateName: this.templateName,
});

When change use addControl

this.templateName.valueChanges.subscribe(val => {
      if (val && this.templateNameMap.hasOwnProperty(val)) {
        const variables = {};
        for (const key of Object.keys(this.templateNameMap[val])) {
          variables[key] = new FormControl("", [Validators.required]);
        }
        this.form.addControl("templateVariables",this.fb.group(variables))
      }
      //I use this.templateVariables to "point" to the formGroup created
      this.templateVariables=(this.form.get('templateVariables') as FormGroup);
    });

Finally, for iterating, if you use Angular 8 -why do you use Angular 6?- you can use |keyvalue

<form formGroupName="templateVariables">
      <input *ngFor="let varName of templateVariables.controls| keyvalue"
      [formControlName]="varName.key">
      <br>
</form>

your forked stackblitz

NOTE: Always we work with dinamic reactiveForms it's good add to the .html some like {{form?.value|json}} to see if we are creating the form as we want

Upvotes: 1

Related Questions