I am trying to build a data-table compatible with FormGroup & FormArray. I will pass header details and rows to this component with parentForm group.
I have created a small add button, on clicking it, I will add new items dynamically. In this case, UI is updating fine, but if I print formGroup.value(), I am getting only the initial value passed. Not the updated formControl. I'm not sure what I am missing.
export class FormTableComponent implements OnChanges {
@Input() headers: Array<string>;
@Input() rows: Array<any>;
@Input() parentFG: FormGroup;
@Input() entriesName: string;
get entries(): FormArray {
return <FormArray>this.parentFG.get(this.entriesName);
}
constructor(private fb: FormBuilder, private cd: ChangeDetectorRef) {}
ngOnChanges() {
this.createFormControls();
}
createFormControls() {
this.parentFG.controls[this.entriesName] = this.fb.array([]);
this.rows.forEach(row => {
this.entries.controls.push(this.fb.group(row));
});
}
}
You have a couple of issues: 1. you push new row to controls of FormArray other than FormArray itself
this.entries.controls.push(this.fb.group(row));
should be
this.entries.push(this.fb.group(row));
2. don't create new FormArray everytime and reload every single row when invoke createFormControls()
, you can access it by your get entries()
method
Solution 1:
Check length of entries
, if it is 0, initialize it with rows
otherwise just push last row into the existing FormArray
createFormControls() {
const keys = Object.keys(this.entries.value);
if( keys.length === 0) {
this.rows.forEach(row => {
this.entries.push(this.fb.group(row));
});
} else {
const row = this.rows[this.rows.length - 1];
this.entries.push(this.fb.group(row));
}
}
Solution 2:
Personally, I prefer putting createFormArray()
and appendTo()
or popFrom()
into the parent Component. It is clean and easy read. We don't need ChangeDetectionRef
in this case.
I have moved createFormControls()
from form-table
component to dummy
component and rename it to createFormArray()
and changed addNewRow()
a little bit, now everything works properly
// create FormArray once
createFormArray() {
const elements: any[] =[];
this.rows.forEach(row => {
elements.push(this.fb.group(row));
});
return this.fb.array(elements);
}
addNewRow() {
const newRow = {
name: 'NAFFD',
age: 12,
place: 'TN'
};
this.rows.push(newRow); // update rows
const persons = this.dummyForm.get('persons') as FormArray;
persons.push(this.fb.group(newRow)); // update FormArray
}
When initializing your dummy form, do below:
this.dummyForm = this.fb.group({
persons: this.createFormArray(),
store: this.fb.group({
branch: '',
code: ''
})
});
Hope it helps and happy coding!