Search code examples
angularangular-reactive-forms

Designing nested reactive forms from nested classes


I have the following classes:

class License {
   name:string;
   .. lots of other fields.
   nameAttributes:NameAttributes[];
}

class nameAttributes:NameAttributes{
   index:number;
   attribute:string;
}

I know I can created the form like this, but it requires that I manually create each field(control) and every time the licences class changes, I have to update the class and this formGroup with the new fields.

       this.licenseForm = formBuilder.group({
          name:['name value'],
          otherFields:['their values'],
          nameAttributes: this.formBuilder.array([
            this.formBuilder.group({
              index:[1],
              attribute:["attr1"]
            }),
            this.formBuilder.group({
              index:[2],
              attribute:["attr2"]
            })
          ])
      });

I would prefer if I could just pass the license class into formBuilder and it would create the necessary FormGroups automatically and make them available based on their name, so the following would create two groups, a "license" group and a nested "nameAttributes" group with all of the associated controls for license and nameAttributes.

      this.licenseForm = formBuilder.group({
        license:formBuilder.group(license)
      });

Am I missing something or is this just not possible without some serious class introspection code?


Solution

  • If your object has data, of course you can do it

    Take a look to this stackblitz

    You has a function like

      createForm(data:any):FormGroup
      {
        const group=new FormGroup({});
        for (let key in data)
        {
          if (Array.isArray(data[key])) //if is an array
          {                             //first create the formArray
            group.addControl(key,new FormArray([this.createForm(data[key][0])]))
            for (let i=1;i<data[key].length;i++)  //after add the rest of the elements
              (group.get(key) as FormArray).push(this.createForm(data[key][i]))
          }
          else
          {
            if (typeof(data[key])=="object") //if is an object we add a formGroup
              group.addControl(key,this.createForm(data[key]))
            else  //add a simple control
              group.addControl(key,new FormControl(data[key]))
          }
        }
        return group
      }
    

    And call it as

    this.form=this.createForm(this.obj)