skip to Main Content

i’m getting a typescript error: Typescript error when trying to implement nested reactive forms in angular.

I can’t understand at what part it becomes an AbstractControl if i’m sending a FormGroup from the beggining

i have this parent component:

import { Component, EventEmitter, Inject, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
import { ClientsService } from 'src/app/services/clients.service';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ContactFormComponent } from '../contact-form/contact-form.component';

@Component({
  selector: 'client-form',
  templateUrl: './client-form.component.html',
  styleUrls: ['./client-form.component.css']
})

export class ClientFormComponent implements OnInit {

  form!: FormGroup;
  submitted = new EventEmitter();

  client: any = {};
  
  constructor(
    private fb: FormBuilder, 
    private ClientSrv: ClientsService, 
    @Inject(MAT_DIALOG_DATA) data: any) {
      if(data) {
        this.client = data;
      }
  };
  
  ngOnInit() {
    this.createForm();
  }

  get contactsArray(): FormArray {
    return this.form?.get('contacts') as FormArray;
  }
  
    
  createForm(): void {
    this.form = this.fb.group({
      'id': [this.client.id],
      'client_name': [this.client.client_name, [Validators.required, Validators.minLength(8)]],
      'client_id': [this.client.client_id, Validators.required],
      'address': [this.client.address, Validators.required],
      'company_email': [this.client.company_email, [Validators.required, Validators.email]],
      'contacts': this.fb.array([ ContactFormComponent.createContactItem() ])
    });
  }
    
  submitForm(update: string): any {
    console.log(this.form.value)
  }
}

and another component that is ContactFormComponent.createContactItem() which goes into the FormArray:

import { Component, Input } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'contact-form',
  templateUrl: './contact-form.component.html',
  styleUrls: ['./contact-form.component.css']
})

export class ContactFormComponent {

  @Input() contactForm!: FormGroup;

  static createContactItem(): FormGroup {
    return new FormBuilder().group({
      'name': [null, [Validators.required]],
      'phone': [null, [Validators.required]],
      'email': [null, [Validators.required, Validators.email]],
    });
  }
  

}

this is the parent component template where i get the error:

<mat-dialog-content>
  <form [formGroup]="form" (ngSubmit)="client.id ? submitForm('update') : submitForm('new')" autocomplete="false">
    <h3>Client Info</h3>
    <form-input name="client_name" type="text" formControlName="client_name" ></form-input>
    <form-input-errors [control]="form.get('client_name')"></form-input-errors>
    <br />
    <form-input name="client_id" type="text" formControlName="client_id" ></form-input>
    <form-input-errors [control]="form.get('client_id')"></form-input-errors>
    <br />
    <form-input name="address" type="text" formControlName="address" ></form-input>
    <form-input-errors [control]="form.get('address')"></form-input-errors>
    <br />
    <form-input name="company_email" type="email" formControlName="company_email" ></form-input>
    <form-input-errors [control]="form.get('company_email')"></form-input-errors>
    <br />
    <h3>Contacts</h3>
    <ng-container *ngFor="let contactForm of contactsArray.controls">
      <!-- // HERE I GET THE ERROR Type 'AbstractControl<any, any>' is missing the following properties from type 'FormGroup<any>' -->
      <contact-form [contactForm]="contactForm" ></contact-form> 
    </ng-container>
    <button type="submit" class="btn btn-sm btn-primary" [disabled]="form.invalid">{{ client.id ? "Update" : "Create" }}</button>
  </form>  
</mat-dialog-content>

i could only get it to work if i change in child component the variable to Any instead of FormGroup but that would be me not understanding why it is happening. Please help, what is the correct way of doing this. thanks

2

Answers


  1. The issue you’re having here is that FormGroup.get() returns an AbstractControl because it can be a FormGroup, FormControl or FormArray. I’d suggest that you change the input type to AbstractControl and then either cast or narrow it to a FormGroup where necessary. Does that make sense?

    Login or Signup to reply.
  2. You can change your Input using a setter

    contactForm!: FormGroup; //<--declare the contactForm
    @Input('contactForm') set _contactForm(value:AbstractControl){
       this.contactForm=value as FormGroup  //"cast" the AbstractControl
    }
    

    Before strict mode, the compilator not take account this

    From Angular 16 you can also use transform

    @Input({transform:(value:any)=>value as FormGroup}) contactForm!:FormGroup
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search