I have been working on developing reusable form input components using Angular's reactive forms.
However, I am currently encountering challenges with my FormArray input component.
To overcome some issues, I had to resort to using double-type casting:
get arrayGroup(): FormGroup {
return this.formArray as AbstractControl as FormGroup;
}
Without wrapping the input HTML within a container like this:
<div [formGroup]="arrayGroup"></div>
I was facing the following error:
NG01053: formGroupName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it to an existing FormGroup instance (you can create one in your class).
Although my current solution is functional, I believe there must be a more efficient way to handle this.
As part of my approach, I have included two components: a form and an input.
** Components Overview **
// FILENAME: forms.component.ts
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
FormArray,
FormBuilder,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { ArrayInputComponent } from './array-input/array-input.component';
@Component({
selector: 'app-forms',
standalone: true,
imports: [ArrayInputComponent, CommonModule, ReactiveFormsModule],
template: `
<div>
<h1>Forms</h1>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<app-array-input [formArray]="formArray"></app-array-input>
<button>Submit</button>
</form>
</div>
`,
})
export class FormsComponent implements OnInit {
form: FormGroup = this.fb.group({});
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.form.addControl('formArray', this.fb.array([]));
}
get formArray() {
return this.form.get('formArray') as FormArray;
}
onSubmit() {
console.log('Form valid:', this.form.valid);
console.log('Form values:', this.form.value);
}
}
// FILENAME: ./array-input/array-input.component
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import {
AbstractControl,
FormArray,
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
@Component({
selector: 'app-array-input',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
template: `
<div [formGroup]="arrayGroup">
<h1>Array Input</h1>
<button type="button" (click)="add()">Add</button>
<ng-container *ngFor="let item of this.formArray.controls; let i = index">
<div [formGroupName]="i">
<input full placeholder="name" formControlName="name" />
<input placeholder="relation" formControlName="relation" />
</div>
</ng-container>
</div>
`,
})
export class ArrayInputComponent {
@Input() formArray!: FormArray;
constructor(private fb: FormBuilder) {}
add() {
const item = this.fb.group({
name: ['', [Validators.required]],
relation: [],
});
this.formArray.push(item);
}
get arrayGroup(): FormGroup {
return this.formArray as AbstractControl as FormGroup;
}
}
Using Angular version 17