You are diving into the deep end for sure, trying to build a dynamic reactive form within the scope of an *ngFor
is a challenge. I will walk you through it the best I can.
You will need to create an array for controls, in your constructor create your form setting formArrayName
as an empty array using this.formBuild.array([])
... call this whatever you want, I just used formArrayName
for demonstration purposes.
After the form is instantiated with an empty array call this.buildForm()
constructor(private formBuilder: FormBuilder) {
this.thisIsMyForm = new FormGroup({
formArrayName: this.formBuilder.array([])
})
this.buildForm();
}
In your buildForm()
iterate over your data[]
and push controls for each index while assigning the default value and a default state of disabled.
buildForm() {
const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
Object.keys(this.data).forEach((i) => {
controlArray.push(
this.formBuilder.group({
name: new FormControl({ value: this.data[i].name, disabled: true }),
type: new FormControl({ value: this.data[i].type, disabled: true })
})
)
})
console.log(controlArray)
}
Please Note: console.log(controlArray.controls) results in the following output... each index is a FormGroup with two controls name
and type
0: FormGroup
1: FormGroup
2: FormGroup
In your html you will need to establish a container hierarchy that mimics the thisIsMyForm
you just created.
- parent:
thisIsMyForm
- child:
formArrayName
- grandchild:
i as formGroupName
grandchild is important because it matches the console log of controlArray.controls
in previous step
<form id="myForm" [formGroup]="thisIsMyForm">
<div [formArrayName]="'formArrayName'">
<mat-card *ngFor="let x of data; let i = index">
<div [formGroupName]="i">
Create edit and save buttons based on control disabled state
<button *ngIf="formControlState(i)" (click)="toggleEdit(i)">Enable Edit</button>
<button *ngIf="!formControlState(i)" (click)="toggleEdit(i)">Save</button>
Create methods in component to receive the index as an argument and handle logic to hide buttons and toggle input fields enable and disable state.
toggleEdit(i) {
const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
if(controlArray.controls[i].status === 'DISABLED'){
controlArray.controls[i].enable()
}else{
controlArray.controls[i].disable()
}
}
formControlState(i){
const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
return controlArray.controls[i].disabled
}
Submit button that console.log's the form value when clicked... also disable button while any of the input formControls are in enabled state.
<button [disabled]="thisIsMyForm.get('formArrayName').enabled" (click)="onSubmit()">Submit Form</button>
onSubmit() {
// Here I would like to be able to access the values of the 'forms'
console.log(this.thisIsMyForm.value)
}
Stackblitz
https://stackblitz.com/edit/dynamic-form-ngfor-otbuzn?embed=1&file=src/app/app.component.ts