Angular 17 - Error when creating reactive dynamic form array with child component

160 views Asked by At

I'm trying to create a dynamic form array in Angular 17 with a child component handling part of the input. However, I'm encountering an error:

Type 'AbstractControl<any, any>' is missing the following properties from type 'FormGroup': controls, registerControl, addControl, removeControl, and 2 more.

Here's my code:

Parent component:

@Component({
  selector: 'app',
  template: `
  <form [formGroup]="categoryForm" (ngSubmit)="onSubmit()">
    <div formArrayName="categories" class="sections">
      <div *ngFor="let category of categories.controls; let i=index">

        <ng-container [formGroupName]="i">
          <!-- CHILD COMPONENT -->
          <app-category [formGroup]="category" [categories]="categories"  [index]="i"></app-category>

          <!-- ARRAY INPUTS -->
          <!-- <div style="border: 1px solid blue; padding: 10px; width: 800px; margin: 5px; background: pink;">
            <p><strong>Category : {{i+1}}</strong></p>
            Category ID :
            <input type="text" formControlName="categoryID" />
            Category Name:
            <input type="text" formControlName="categoryName" />

            <button type="button" class="remove" (click)="removeCategory(i)">Remove Category</button>
          </div> -->
        </ng-container>
      </div>
    </div>
    <button class="btn" type="button" (click)="addCategory()">Add Category</button>
    <button class="btn" type="submit">Submit</button>
  </form>

{{this.categoryForm.value | json}}
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [ReactiveFormsModule, JsonPipe, NgFor, CategoryComponent],
})
export class AppComponent {
  categoryForm!: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    this.categoryForm = this.fb.group({
      categories: this.fb.array([]),
    });
  }

  get categories(): FormArray {
    return this.categoryForm.get('categories') as FormArray;
  }

  addCategory() {
    this.categories.push(
      this.fb.group({
        categoryID: '',
        categoryName: '',
        sections: this.fb.array([]),
      })
    );
  }

  removeCategory(catIndex: number) {
    this.categories.removeAt(catIndex);
  }

  onSubmit() {
    console.log(this.categoryForm.value);
  }
}

Child component:

@Component({
  selector: 'app-category',
  template: `
  <form [formGroup]="formGroup">
    <div style="border: 1px solid blue; padding: 10px; width: 800px; margin: 5px; background: pink;">
      <p><strong>Category : {{index+1}}</strong></p>
      Category ID :
      <input type="text" formControlName="categoryID" />
      Category Name:
      <input type="text" formControlName="categoryName" />

      <button type="button" class="remove" (click)="removeCategory()">Remove Category</button>
    </div>
  </form>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [ReactiveFormsModule, NgFor],
})
export class CategoryComponent {
  @Input() categories!: FormArray;
  @Input() formGroup!: FormGroup;
  @Input() index!: number;

  removeCategory() {
    this.categories.removeAt(this.index);
  }
}

I've created a form array in the parent component and tried to loop through it using *ngFor, passing each form group to the child component. The child component receives the form group via @Input() and handles part of the input fields.

Can someone help me understand why this error is occurring and how to resolve it? Thank you!

1

There are 1 answers

2
Yong Shun On BEST ANSWER
  1. You need to cast the AbstractControl to FormGroup.
  2. Remove [formGroupName]="i" from <ng-container> as it is not needed.
<ng-container>
    <!-- CHILD COMPONENT -->
    <app-category [formGroup]="categoryFormGroup(i)" [categories]="categories"  [index]="i"></app-category>
</ng-container>
categoryFormGroup(i: number) {
  return this.categories.get(`${i}`) as FormGroup;
}

Demo @ StackBlitz