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
The issue you’re having here is that
FormGroup.get()
returns anAbstractControl
because it can be aFormGroup
,FormControl
orFormArray
. I’d suggest that you change the input type toAbstractControl
and then either cast or narrow it to aFormGroup
where necessary. Does that make sense?You can change your Input using a setter
Before strict mode, the compilator not take account this
From Angular 16 you can also use transform