I am working to recreate the nested array for Angular Reactive Forms.
Existing Nested Array.
nestedArray = [{
id:'abc',
required:true,
children:[{
id:"bcd",
parentId:"abc",
required:true,
children:[{
id:"cde",
parentId:"bcd",
required:false,
children:[{
id:"def",
parentId:"cde",
required:true,
children:[{
id:"efg",
parentId:"def",
required:false,
}]
},
{
id: "xyz",
parentId: "cde",
required: true,
}]
}]
}]
}]
Recreate this array for Angular Reactive Forms
nestedArray= this.fb.group({
abc: [''],
bcd: this.fb.group({
cde: [''],
efg: [''],
}),
});
Above array is incorrect, looking for the right way to create the children in Angular Reactive Form.
Thanks
You need make a recursive function that return a FormControl or a FormGroup
form = new FormArray(this.nestedArray.map(x=>{
const group=new FormGroup({})
group.addControl(x.id,this.getGroup(x))
return group
}));
getGroup(data: any) {
if (!data.children)
return new FormControl()
const group = new FormGroup({});
if (data.children) {
data.children.forEach(x=>{
group.addControl(x.id,this.getGroup(x))
})
}
return group;
}
See stackblitz
Update really the answer is wrong, becaouse we has no form control to the "parents". the function must be like
form = new FormArray(this.nestedArray.map(x=>this.getGroup(x)))
getGroup(data: any) {
if (!data.children)
{
return new FormControl)
}
const group = new FormGroup({});
group.addControl(data.id,new FormControl())
if (data.children) {
data.children.forEach(x=>{
group.addControl(x.id,this.getGroup(x))
})
}
return group;
}
Well, the question is how conrol this crazy form. We can try create a "recursive template", but I think it's better another aproach. Imagine you has an array of elements, each one with three porperties: "index","label" and "control". And control is a reference to the FormControl of our form. Then we can construct an .html like
<div *ngFor="let item of controls">
<span [style.margin-left]="item.index*10+'px'">{{item.label}}</span>
<input [formControl]="item.control">
<span *ngIf="item.control.errors?.required">*</span>
</div>
easy no? just use directly [formControl]
and item.control.errors
or item.control.touched
Well, for this first declare an empty array
controls:any[]=[];
And change the fuction so we add the group in two steps: 1.-create the formControl, 2.-Add to the group, the third step is add to our array an object with {label,control and "index"}. Well it's typical when we has a recursive function to want know the "index" of the recursion.
//we pass as index 0 at first
form = new FormArray(this.nestedArray.map(x=>this.getGroup(x,0)))
getGroup(data: any,index:number) {
if (!data.children)
{
//create the control
const control=new FormControl('',data.required?Validators.required:null)
//add to the array this.controls
this.controls.push({control:control,label:data.id,index:index})
//return control
return control
}
const group = new FormGroup({});
index++
//create the control
const control=new FormControl('',data.required?Validators.required:null)
//add to the array this.controls
this.controls.push({control:control,label:data.id,index:index})
//add the control to the group
group.addControl(data.id,control)
if (data.children) {
data.children.forEach(x=>{
group.addControl(x.id,this.getGroup(x,index++))
})
}
return group;
}
Well, In the stackblitz add the property "value" to our complex object, to show how can do it, and we use as "label" the "id" -perhafs our complex object need a new property label-