I want to create FormGroups/FormArrays inside mat-expansion-panel based on number of records I have in my database.
I have a group table
id | desc
1 | Group 1
2 | Group 2
I have detail table
id | desc | group_id
1 | Detail 1.1 | 1
2 | Detail 1.2 | 1
3 | Detail 2.1 | 2
Now, I have this codes and it will loop based on number of records
HTML
<mat-expansion-panel *ngFor="let group of groups"> <!-- based on group table -->
<form [formGroup]="group.formGroup">
<div formArrayName="group.formArray" >
<div *ngFor="let detail of details"> <!-- based on detail table -->
</div>
</div>
</form>
</mat-expansion-panel>
TS
????????
I know how to create form group and form array but doing it based on number of records that is divided by mat-expansion-panel... There's where my problem.
Really I don't know what king of formGroup/formArray you want to create. I suppose you want a formArray of formGroup, each formGroup has as formControl "id","desc" and a formArray "detail". So we can get something like
[
{
"id": 1,
"desc": "group1",
"detail": [
{
"id": 1,
"desc": "Detail 1.1."
},
{
"id": 2,
"desc": "Detail 1.2."
}
]
},
{
"id": 2,
"desc": "group2",
"detail": [
{
"id": 3,
"desc": "Detail 2.1."
}
]
}
]
to manage FormArrays of FormGroup, it's usefull create function that return a formGroup, like
createGroup(data:any):FormGroup
{
data=data || {id:null,desc:null,detail:null}
return new FormGroup({
id:new FormControl(data.id),
desc:new FormControl(data.desc),
detail:data.detail && data.detail.length?
new FormArray(data.detail.map(detail=>this.createDetail(detail))):
new FormArray([])
})
}
createDetail(data:any):FormGroup
{
data=data || {id:null,desc:null}
return new FormGroup({
id:new FormControl(data.id),
desc:new FormControl(data.desc),
})
}
Well if we has some like
group=[{id:1,desc:"group1"},{id:2,desc:"group2"}]
detail=[{id:1,desc:"Detail 1.1.",group_id:1},
{id:2,desc:"Detail 1.2.",group_id:1},
{id:3,desc:"Detail 2.1.",group_id:2}
]
We can create a formArray in ngOnInit
this.form=new FormArray(this.group.map((x:any)=>{
return this.createGroup({
...x,
detail:this.detail.filter(d=>d.group_id==x.id)
})
}))
See how we create a FormArray transform each element of this.group to a FormGroup. we pass to our function as "data" the value of each "group" and a new protertie, "detail" that it's an array, the values of details which groupId are equals to id
Well it's the difficult part. the funny is place all in an accordeon
<form *ngIf="form" [formGroup]="form">
<mat-accordion>
<mat-expansion-panel *ngFor="let grp of form.controls" [formGroup]="grp">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-form-field>
<input matInput formControlName="id">
</mat-form-field>
<mat-form-field>
<input matInput formControlName="desc">
</mat-form-field>
</mat-panel-title>
</mat-expansion-panel-header>
<div formArrayName="detail">
<div *ngFor="let detail of grp.get('detail').controls;let i=index" [formGroupName]="i">
<mat-form-field>
<input matInput formControlName="id">
</mat-form-field>
<mat-form-field>
<input matInput formControlName="desc">
</mat-form-field>
</div>
</div>
</mat-expansion-panel>
</mat-accordion>
</form>
see that we are using the way *ngFor="let grp of form.controls" [formGroup]="grp"
to get the group of the formArray. This is the manner to manage a FormArray, put <form [formGroup]="myFormArray">
and loop over myFormArray.controls
You can see in stackblitz
NOTE: I put as editable and part of the form the ids too, when really I think it's not necesary
NOTE2: in a submit, you need create a new table of details mapping the form.value