Dragos Stoica
Dragos Stoica

Reputation: 1935

Angular 14 reactive forms addControl not working

I recently migrated to Angular 14 and this line of code is throwing an exception when trying to dynamically add new from controls:

formGroup.addControl("agreement", new FormControl(""));

error:

error TS2769: No overload matches this call. 
FormControl<...>; }>' is not assignable to method's 'this' of type 'FormGroup<{ [key: string]: AbstractCont

rol<any, any>; }>'. ....

when hovering over the line with error I get this text:

Add a control to this group. In a strongly-typed group, the control must be in the group's type (possibly as an optional key). If a control with a given name already exists, it would not be replaced with a new one. If you want to replace an existing control, use the FormGroup#setControl setControl method instead. This method also updates the value and validity of the control. Is there a workaround for this?

Please find here the problem: stackblitz demo

UPDATE:

This is the full code causing the problem:

 private test_formGroup() {
    const formGroup = new FormGroup({
      requestReference: new FormControl(''),
      emailRecipient: new FormControl([Validators.required, Validators.email]),
      emailBodyMessage: new FormControl('', Validators.required),
      requestDetails: new FormControl(''),
    });

    if (true) {
      //real condition here
      formGroup.addControl('termsOfAgreement', new FormControl(''));
    }
  }

if I add the control at the FormGroup generation it works:

  const formGroup = new FormGroup({
      requestReference: new FormControl(''),
      emailRecipient: new FormControl([Validators.required, Validators.email]),
      emailBodyMessage: new FormControl('', Validators.required),
      requestDetails: new FormControl(''),
      termsOfAgreement: new FormControl('')
    });

    if (true) {
      //real condition here
      formGroup.addControl('termsOfAgreement', new FormControl(''));
    }

but what happens when you have complex logic and you don't know from the beginning all the controls that need to be added?! what's the benefit of "addControl" if you need to specifically add it at the FormGroup creation time ?!

Upvotes: 7

Views: 7686

Answers (4)

krisged
krisged

Reputation: 1

There is a simple way to do it - just type your form group. Example:

const formGroup = new FormGroup<Record<string, AbstractControl>({

or

const formGroup = new FormGroup<Record<string, FormControl>({

no form builders or any other workarounds are needed. This is because addControl uses strongly-typed group, so as keys it would use the current fields in FormGroup. In you case they are: requestReference, emailRecipient, emailBodyMessage, and requestDetails. So when you want to add new FormControl with new name (agreement), it says you use wrong type

Upvotes: 0

Fiehra
Fiehra

Reputation: 797

I came across the same error after upgrading angular to v14. I fixed the error by using the UntypedFromGroup as explained in the docs here:

https://angular.io/guide/typed-forms

as mentioned in Eliseo's comment angular 14 now uses typed forms by default. You can fix the IDE error by using UntypedFormGroup like this:

import { FormControl, UntypedFormGroup, Validators } from '@angular/forms';

private test_formGroup() {
    const formGroup = new UntypedFormGroup({
      requestReference: new FormControl(''),
      emailRecipient: new FormControl([Validators.required, Validators.email]),
      emailBodyMessage: new FormControl('', Validators.required),
      requestDetails: new FormControl(''),
    });

    if (true) {
      formGroup.addControl('termsOfAgreement', new FormControl(''));
    }
  }

By using a UntypedFormGroup the addControl method will work just like in angular v13

Upvotes: 6

Aouidane Med Amine
Aouidane Med Amine

Reputation: 1681

you can't add a fromControl directly like that , you need to use the formBuilder and formGroup.

method 1 :

 addControl(): void {
      this.formGroup = this.fb.group({
         ...this.formGroup.controls,   // <-- push to the existing formGroup controls
         agreement: [''],
      });
    }

method 2 :

addControl(): void {
    this.formGroup.addControl('agreement', this.fb.control(''));
}

i have fixed your code in stackblitz too :

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

@Component({
  standalone: true,
  selector: 'app-name',
  template: `
    <ng-content></ng-content>, {{ name }}.
  `,
  styles: [``],
})
export class NameComponent {
  formgroup: FormGroup;
  constructor(private fb: FormBuilder) {}
  @Input() name = '';

  private test_formGroup() {
    this.formgroup = new FormGroup({
      requestReference: new FormControl(''),
      emailRecipient: new FormControl([Validators.required, Validators.email]),
      emailBodyMessage: new FormControl('', Validators.required),
      requestDetails: new FormControl(''),
    });
    this.fb.group(this.formgroup);
    if (true) {
      //real condition here
      this.formgroup.addControl('termsOfAgreement', this.fb.control(''));
    }
  }
}

you have no more errors :

enter image description here

Upvotes: 4

Aniket
Aniket

Reputation: 401

I did some changes in your code and build the form using FormBuilder Please have a look and accept the answer if this resolves your problem.

https://stackblitz.com/edit/angular-v14-playground-zsq82f?file=src%2Fname.component.ts

Upvotes: 1

Related Questions