I am trying to build a nested reactive form in Angular 5. I am able to push items at one level, but unable to push item at second level.
ngOnInit() {
this.orderForm = this.formBuilder.group({
customerName: '',
email: '',
items: this.formBuilder.array([this.createItem()])
});
}
createItem(): FormGroup {
return this.formBuilder.group({
name: 'a',
description: 'b',
price: 'c',
//subItems: this.formBuilder.array([this.createSubItem()])
});
}
//createSubItem(): FormGroup {
//return this.formBuilder.group({
//subname: 'abc'
//});
//}
addItem(): void {
this.items = this.orderForm.get('items') as FormArray;
//this.subItems = this.items.get('subItems') as FormArray;
//this.subItems.push(this.createSubItem());
this.items.push(this.createItem());
}
In the above code the uncommented code is working fine with push. I have further subItems inside items, and commented code is the one I am trying to achieve, but it is not working.
Can any body show me how to achieve this?
For uncommented code, I am showing data in html like this and it is working well. If any body have solution at code level, please also tell me how to update html for nested items as well.
<form [formGroup]="orderForm">
<div formArrayName="items" *ngFor="let item of orderForm.get('items').controls; let i = index;">
<div [formGroupName]="i">
<input formControlName="name" placeholder="Item name">
<input formControlName="description" placeholder="Item description">
<input formControlName="price" placeholder="Item price">
</div>
</div>
<input type="button" value="sldkj" (click)="addItem()">
</form>
SOLUTION:
First of all I managed to pre-populate values like this.
obj = [
{
'name': "umair",
'description': "desc1",
'subItems': [
{
'subname': 'value'
},
{
'subname': 'value2'
},
{
'subname': 'value3'
}
]
},
{
'name': "ali",
'description': "desc2",
'subItems': [
{
'subname': 'valu4'
},
{
'subname': 'value5'
},
{
'subname': 'value6'
}
]
}
]
ngOnInit() {
this.createForm(this.obj);
console.log(this.orderForm);
}
createForm(obj) {
var arr = [];
for (var i = 0; i < obj.length; i++) {
arr.push(this.createItem(obj[i]));
}
this.orderForm = this.formBuilder.group({
items: this.formBuilder.array(arr)
});
}
createItem(obj): FormGroup {
var subArr = [];
for (var i = 0; i < obj.subItems.length; i++) {
subArr.push(this.createSubItem(obj.subItems[i]));
}
return this.formBuilder.group({
name: obj.name,
description: obj.description,
subItems: this.formBuilder.array(subArr)
});
}
createSubItem(subItem): FormGroup {
return this.formBuilder.group({
subname: subItem.subname
});
}
After help in 'marked' answer below, I managed to add subitem and populate in html like below.
<form [formGroup]="orderForm">
<!-- <label>{{item.get('name').value}}</label> -->
<div formArrayName="items" *ngFor="let item of orderForm.controls.items.controls; let i = index;">
<div formGroupName="{{i}}">
<!-- <label>{{item.get('name').value}}</label> -->
<input formControlName="name" placeholder="Item name">
<input formControlName="description" placeholder="Item description">
<input type="button" value="subAdd" (click)="addSubItems(i)">
<div formArrayName="subItems" *ngFor="let subItem of item.controls.subItems.controls; let idx = index;">
<div formGroupName="{{idx}}">
<!-- <label>{{subItem.get('subname').value}}</label> -->
<input formControlName="subname" placeholder="Item name">
</div>
</div>
</div>
</div>
</form>
code
addSubItems(_index: any): void {
var a = this.orderForm['controls']['items']['controls'][_index] as FormGroup;
this.subItems = a.get('subItems') as FormArray;
var newSubItem = {
'subname': 'value6'
}
this.subItems.push(this.createSubItem(newSubItem));
}