Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactiveForms with dynamic recursive templates

Here is my problem.

Online Example of the issue

I have a dynamic JSON that I need to convert to a form. So, I used reactive forms and by going through all the properties of the JSON I create either a FormGroup or FormControl, in this way:

sampleJson ={prop1:"value1", prop2: "value2",...}

...

  myForm: FormGroup;
  myKeys=[];
    ...

  ngOnInit() {
    this.myForm = this.getFormGroupControls(this.sampleJson, this.myKeys);

  }

getFormGroupControls(json:any,keys): FormGroup{
    let controls = {};
    let value = {};

    for (let key in json) {
      if (json.hasOwnProperty(key)) {

        value = json[key];
        if (value instanceof Object && value.constructor === Object) {

          keys.push({"key":key,children:[]});
          controls[key] = this.getFormGroupControls(value,keys[keys.length-1].children);
        } else {

          keys.push({"key":key,children:[]});
          controls[key] = new FormControl(value);

        }
      }
    }

    return new FormGroup(controls);
  }

After doing so, I use recursive templates to build the form, if I do not use recursive templates I get the form to work. However with recursive templates I am getting errors:

<form [formGroup]="myForm">

  <div class="form-group">


    <ng-template #nodeTemplateRef let-node>

      <div class="node">
        <div  *ngIf="node.children.length">
          {{"section [formGroupName]="}} {{ getNodeKey(node) }}
          <section style="display:block;margin:20px;border:solid 1px blue;padding-bottom: 5px;"
            [formGroupName]="getNodeKey(node)" >
            <h1>{{ node.key }}</h1>
            <ng-template
              ngFor
              [ngForOf]="node.children"
              [ngForTemplate]="nodeTemplateRef">
            </ng-template>
          </section>
          {{"end of section"}}
        </div>
        <div  *ngIf="!node.children.length">
          <label [for]="node.key">{{node.key}}</label>&nbsp;
          <input  type="text" [id]="node.key"
                  class="form-control">
        </div>
      </div>

    </ng-template>

    <ng-template *ngFor="let myKey of myKeys"
                 [ngTemplateOutlet]="nodeTemplateRef"
                 [ngTemplateOutletContext]="{ $implicit: myKey   }">
    </ng-template>

  </div>

FormerComponent.html:25 ERROR Error: Cannot find control with name: 'road'

That corresponds to this sample JSON:

"address": {
        "town": "townington",
        "county": "Shireshire",

        "road": {
          "number": "1",
          "street": "the street"
        }

I have is being displayed, so I know the elements are there. What am I missing?

like image 670
Dalorzo Avatar asked Jan 16 '20 18:01

Dalorzo


People also ask

What is the difference between Reactive forms and template forms?

Template Driven Forms are based only on template directives, while Reactive forms are defined programmatically at the level of the component class. Reactive Forms are a better default choice for new applications, as they are more powerful and easier to use.

Can NgModel be used in Reactive forms?

You can use [(ngModel)] with Reactive forms. This will a completely different directive than the one that would be used without the formControlName . With reactive forms, it will be the FormControlNameDirective . Without the formControlName , the NgModel directive would be used.

What is FormBuilder in Reactive forms?

In Angular, a reactive form is a FormGroup that is made up of FormControls. The FormBuilder is the class that is used to create both FormGroups and FormControls.

What is a reactive dynamic forms application?

A reactive dynamic forms application, which allows you to define forms containing some dynamic fields of different types (Text, Number, Checkbox, Date, DateTime, Time, Dropdown, Multiple Tags, Radio Group), then you can use these forms in any reactive/mobile screen. Which holds the entities (Form, Section, Field, Option, FieldData, FieldType).

What is the difference between template-driven forms and reactive forms?

Broadly speaking, with template-driven forms we declare our form model by writing plain-old-fashioned HTML forms and let Angular create a form model out of the DOM. Now, in reactive forms we write that form model in code and then bind instances of FormGroup and FormControl into the DOM.

What is the difference between reactive and a form model?

A form model can be passed from one component to another using input properties. This technique allows building rather sophisticated and complex forms who are composed of several components. Reactive forms are a good fit for that idea, making it relatively easy to build nested forms.

How do I create a dynamic form in React React?

Dynamic Reactive Forms App Component The app component defines the form fields and validators for the dynamic form using an Angular FormBuilder to create an instance of a FormGroup that is stored in the dynamicForm property. The dynamicForm is then bound to the <form> element in the app template below using the [formGroup] directive.


2 Answers

Problem with your current code seems to be that ng-template parent is your app component, so it doesnt take into account other formGroupNames in top templates you defined and always seek in root FormGroup.

It also seems that full group name/control name is not supported in templates (e.g. cant use formGroupName="address.road")

If you need for some reason formGroups -- you can pass them in context to templates. Or you can address formControls directly:

  • remove all formGroupName from template
  • store fullPath: keys.push({"key":key,children:[], fullKey: parent ? parent.fullKey + '.' + key: key}); (you can store FormControl instance itself as well ofc.)
  • and use it: <input type="text" [formControl]="myForm.get(node.fullKey)"

Stackblitz Example

like image 163
Petr Averyanov Avatar answered Oct 21 '22 16:10

Petr Averyanov


Or if you still want form groups / controls hierarchy you can use formGroup and formControl directives by passing them recursively (instead of formGroupName and formControlName)

Stackblits link

NB : same issue here : Recursive ReactiveForm cannot find formGroups inside of template

like image 32
Neji Sghair Avatar answered Oct 21 '22 18:10

Neji Sghair