I want to create a dynamic form that is an array of payments, the user can add a new payment, delete from the array, and edit.
My HTML:
<form [formGroup]="createLoanPaymentsForm" (ngSubmit)="createLoan()">
<ng-container formArrayName="createLoanPaymentsForm">
@for (
createLoanPaymentForm of createLoanPaymentsForm.controls; // here is the error
track $index
) {
<div [formGroup]="createLoanPaymentForm">
<mat-form-field appearance="fill">
<input matInput formControlName="title" placeholder="Lesson title" />
</mat-form-field>
</div>
}
<button mat-mini-fab (click)="addPayment()">Add</button>
</ng-container>
</form>
The configuration of my component:
@Component({
selector: 'app-create-loan-dialog',
standalone: true,
imports: [
MatInputModule,
MatButtonModule,
MatDialogTitle,
MatDialogContent,
MatDialogActions,
MatDialogClose,
ReactiveFormsModule,
MatStepperModule,
],
providers: [
{
provide: STEPPER_GLOBAL_OPTIONS,
useValue: { showError: true },
},
],
templateUrl: './create-loan-dialog.component.html',
})
My FormGroup
:
createLoanPaymentsForm: FormGroup = this.formBuilder.group({
payments: this.formBuilder.array([]),
});
There is an error in my loop, it says:
Type '{ [key: string]: AbstractControl<any, any>; }' must have a 'Symbol.iterator' method that returns an iterator.
The solution for this bug, possible the correct configuration for a FormArray
loop in Angular 17
Your Reactive Form (HTML) structure is incorrect:
formArrayName
with "payments": formArrayName="payments"
.
In the @for
loop, you need to iterate the payments.controls
.
Under the @for
loop, generate each FormGroup
instance with [formGroupName]="index"
.
<form [formGroup]="createLoanPaymentsForm" (ngSubmit)="createLoan()">
<ng-container formArrayName="payments">
@for (payment of payments.controls; track payment; let index = $index) {
<div [formGroupName]="index">
...
</div>
}
<button mat-mini-fab (click)="addPayment()">Add</button>
</ng-container>
</form>
get payments() {
return this.createLoanPaymentsForm.controls['payments'] as FormArray;
}