I'm building dynamic form and want to add form groups 'on the fly'.
Here is my code which almost works:
import {Component, OnInit} from '@angular/core';
import {FormGroup, FormBuilder, FormArray, Validators, FormControl} from "@angular/forms";
export class CombinedComponent implements OnInit {
ltsForm: FormGroup;
constructor(private formBuilder: FormBuilder) {
}
ngOnInit() {
this.ltsForm = this.initFormGroup();
// init products
for (let i = 0; i < 3; i++) { // add dynamically products
this.addProduct();
}
console.log(this.ltsForm); // Array 'prods' is empty
}
// initialize form group, but don't add products yet because they will be added dynamically later
initFormGroup() {
let group = this.formBuilder.group({
products: this.initProductGroup()
});
return group;
}
initProductGroup() {
let group = this.formBuilder.group(
{
//initialize empty formbuilder array
prods: this.formBuilder.array([])
}
);
return group;
}
initProducts() {
return this.formBuilder.group({
id: [''],
value: false, // checkbox value
});
}
addProduct() {
<FormArray>this.ltsForm.controls['products'].value.prods.push(this.initProducts());
console.log(this.ltsForm); // Array 'prods' contains 3 FormGroup elements
}
}
Template:
<form [formGroup]="ltsForm"
novalidate
(ngSubmit)="save(ltsForm)">
<div formGroupName="products">
<div formArrayName="prods">
<div *ngFor="let product of ltsForm.controls.products.value.prods.controls; let i = index">
<div [formGroupName]="i">
<input type="checkbox"
formControlName="value"
id="product_{{ i }}"
name="product_{{ i }}">
</div>
</div>
</div>
</div>
<button type="submit"
[disabled]="!ltsForm.valid">
Submit
</button>
</form>
In method addProduct()
I push the whole FormGroup element to the 'prods' array. So at the end the output from console in ngOnInit()
contains just an empty 'prods' array, while the array from console output in addProduct()
method has 3 elements. It looks like this.ltsForm
looses its reference and isn't updating. Any ideas?
UPD: Just found out that if I remove the whole content from template, I get the 'prods' filled with data.
There were a number of small mistakes and complexities, so I pared down your example and built it back up. The Angular team had examples of a nested form array and nested form group that were very helpful. Here was the process (and plnkr):
{ projects: '' }
.Got a group with an array of controls working: { projects: ['a', 'b', 'c'] }
. I skipped prods
, it seemed unnecessary.
<form [formGroup]="ltsForm" novalidate (ngSubmit)="save()">
<div formArrayName="products">
<div *ngFor="let p of products.controls; let i=index">
<input [formControlName]="i">
</div>
</div>
<button type="submit" [disabled]="!ltsForm.valid">
Submit
</button>
</form>
...
export class CombinedComponent implements OnInit {
ltsForm: FormGroup;
get products() { return this.ltsForm.get('products'); }
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.ltsForm = this.formBuilder.group({
products: this.formBuilder.array([])
});
for (let i = 0; i < 3; ++i) {
this.addProduct();
}
}
addProduct() {
this.products.push(this.formBuilder.control(''));
}
save() {
console.log(this.ltsForm.value);
}
}
Final step replace controls in the array with groups:
@Component({
selector: 'combined-component',
template: `
<form [formGroup]="ltsForm" novalidate (ngSubmit)="save()">
<div formArrayName="products">
<div *ngFor="let p of products.controls; let i=index">
<div [formGroupName]="i">
<input formControlName="id">
<input type="checkbox" formControlName="value">
</div>
</div>
</div>
<button type="submit" [disabled]="!ltsForm.valid">
Submit
</button>
</form>
`
})
export class CombinedComponent implements OnInit {
ltsForm: FormGroup;
get products() { return this.ltsForm.get('products'); }
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.ltsForm = this.formBuilder.group({
products: this.formBuilder.array([])
});
for (let i = 0; i < 3; ++i) {
this.addProduct();
}
}
addProduct() {
this.products.push(this.formBuilder.group({
id: '',
value: false
}));
}
save() {
console.log(this.ltsForm.value);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With