Angular Reactive forms formgroup

1.1k views Asked by At

I need to have a formControl for two different arrays under the same node so I could add and delete a respective nested node in the given Reactive form.

Expected JSON Format:

{
  "title": null,
  "days": [
    {
      "date": null,
      "nodes": [
        {
          "type": "leg",
          "from": null,
          "to": null
        },
        {
          "type": "activity",
          "category": null
        }
      ]
    }
  ]
}

I have implemented control on day and node for which I was able to add and delete the form fields respectively however I need separate controls for type leg and activity under nodes.

Is there any way to implement nested formControl in here?

Update: Need two formgroups under a form array, please help to implement in HTML.

initX() {
    return this.fb.group({
      'date': [],
      'nodes': this.fb.array([
        this.initY(),
        this.initZ()
      ]),
    });
  }

  initY() {
    return this.fb.group({
      'type': ['leg'],
      'from': [],
      'to': []
    })
  }

  initZ() {
    return this.fb.group({
      'type': ['activity'],
      'category':[],
      'cost':[]
    })
  }

Error: Cannot find control with path: 'days -> 0 -> nodes -> 1 -> from'

Can find the stackblitz of the sample code here: https://stackblitz.com/edit/angular-ivy-fkgxrr

4

There are 4 answers

0
Eliseo On BEST ANSWER

well, in my another answer, the "nodes" array is like

[
 {"type": "leg","from": null,"to": null,"category": null}
 {"type": "leg","from": null,"to": null,"category": null}
]

A formArray need has all his elements with the sames properties

Question: nodes is only an array with two elements (one for control Leg and another one for control category)?

In this case days is a formArray, each element is a formGroup with two peoperies, one of them is an array (not a formArray) with two elements

form=new FormGroup({
  title:new FormControl()
  days:new FormArray([
     date:new FormControl(),
     nodes:[new FormGroup({...}),new FormGroup({..})]
  ])
})

in this case you can has three getter

get days():FormArray
{
    return this.formGroup.get('days') as FormArray;
}
get leg(index)
{
    return this.days.at(i).get('nodes')[0] as FormGroup
}
get category(index)
{
    return this.days.at(i).get('nodes')[1] as FormGroup
}

And use directly [formGroup] in a div, e.g.

<div [formGroup]="category[i]">
   <input formControlName="from">
   ...
</div>

else I can not understand your json

2
Eliseo On

keethama, step by step. You has a formArray inside a formArray, so make two functions that return a formArray

  get days():FormArray
  {
    return this.formGroup.get('days') as FormArray;
  }
  getNodes(i:number):FormArray
  {
    return this.days.at(i).get('nodes') as FormArray
  }

Well, to create the form divide and use three functions:

  createForm(data:any)
  {
    data=data || {title:null,days:null}
    return new FormGroup({
      title:new FormControl(data.title),
      days:data.days?
           new FormArray(data.days.map(d=>this.createDays(d))):
           new FormArray([])
      
    })
  }
  createDays(data:any=null)
  {
    data=data || {date:null,nodes:null}
    return new FormGroup({
        date:new FormControl(data.date),
        nodes:data.nodes?
              new FormArray(data.nodes.map(x=>this.createNodes(x))):
              new FormArray([])
    })
  }
  createNodes(data:any=null)
  {
    data={type:null,from:null,to:null,category:null,...data}
    return new FormGroup({
      type: new FormControl(data.type),
      from: new FormControl(data.from),
      to: new FormControl(data.to),
      category: new FormControl(data.category)
    })
  }

Well, now take a look to the .html

<form *ngIf="formGroup" [formGroup]="formGroup">
  title:<input formControlName="title">
  <div formArrayName="days">
    <div *ngFor="let groupDays of days.controls;let i=index" [formGroupName]="i">
        date:<input formControlName="date">
        <div formArrayName="nodes">
          <div *ngFor="let groupnodes of getNodes(i).controls;let j=index" [formGroupName]="j">        
            type:<input formControlName="type"><br/>
        from:<input formControlName="from"><br/>

        to:<input formControlName="to"><br/>
        category:<input formControlName="category">
          </div>
        </div>
    </div>
  </div>
</form>

And in ngOnInit

this.formGroup=this.createForm(this.data)

See that if you want to add a new node to the node in index index you use

   this.getNodes(index).push(this.createNodes())

And to add a new node to the days array

   this.days.push(this.createDays())

An incomplete stackblitz

0
Francesco Colamonici On

I see it might not be a full response, because a working sample with nested FormArrays would take some time, but I'm pretty sure you will find interesting and helpful this article (that helped me out in a lot of situations like this):

0
shivshankar alkondwar On

Try using two way data binding. This will simplify your process.

Eg:

<input type="text" name="name" [(ngModel)]="model.name">