Custom component FormControl breaking if reinitializing FormGroup from parent

11,157

Solution 1

I figured out that it is not good to reinitialize formGroup over and over again, because component looses reference to old formGroup.

If setting values is what is needed to show fresh form, .setValue is the solution here:

Component

Instead of reinitializing addForm, check if addForm was initialized previously and if so, only set value for existing FormControls:

if (this.addForm) {
    this.addForm.setValue({
        selectedCountry: null
    })
} else {

    let formTemp: any = {
        selectedCompany: new FormControl(null, [Validators.required]),
    }

    this.addForm = this._formBuilder.group(formTemp);
}

In this way, I figured, reference is not lost to old addForm, so no error occurs.

Solution 2

My solution for that is to replace formControlName with formControl.

Instead of

<my-custom-component formControlName="selectedCompany"></my-custom-component>

use

<my-custom-component [formControl]="addForm.controls['selectedCompany']"></my-custom-component>

or with some getMethod for taking formControl

Works also with error:

There is no FormControl instance attached to form control element with path

where I've used some FormArray.

Solution 3

I found a wierd "solution" to this. So to reset the subcomponents, which use the formGroup and get confused when you swap it out. I use this hack.

comp.ts

public flicker: boolean = false;

reInit() {
    this.flicker = true;

    this.addForm = this._formBuilder.group({
         selectedCompany: new FormControl(null, [Validators.required]),
    });

    setTimeout( () => this.flicker = false, 200); //On very heavy pages, timeout ensures that the flicker hack works as expected.
}

comp.html

<form [formGroup]="addForm" *ngIf="!flicker">
     ...
     <my-custom-component formControlName="selectedCompany"></my-custom-component>
     ...
</form>

Horrendeous hack, which basically enforces the formGroup components to destroy and re-initialize themselves, but desperate times call for desperate measures...

I needed this hack, because I use FormGroup objects to save the results of a form into an interim array of results, each of which can be re-opened and edited at will. In the future, I will be making ngModel based form state saving, to avoid this issue, but a temporary solution is here.

Edit 1

setTimeout( () => this.flicker = false, 200); //On very heavy pages, timeout ensures that the flicker hack works as expected.

There is a better way to synchronously do the flicker

this.flicker = true;
this._changeDetectorRef.detectChanges();
this.flicker = false;
this._changeDetectorRef.detectChanges();

detect changes will synchronously run the change detection and update the view, thus removing the old formgroup.

Share:
11,157

Related videos on Youtube

Mario Petrovic
Author by

Mario Petrovic

Updated on October 22, 2022

Comments

  • Mario Petrovic
    Mario Petrovic over 1 year

    I got a problem when reinitializing formGroup from parent component that is used in my custom component. Error that i get is:

    There is no FormControl instance attached to form control element with name: 'selectedCompany'

    HTML:

    <form [formGroup]="addForm">
         ...
         <my-custom-component formControlName="selectedCompany"></my-custom-component>
         ...
    </form
    

    <my-custom-component> is created according to valid way of creating custom formControl component: https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html#implementing-controlvalueaccessor

    Component

    This is code that initializes formGroup variable addForm:

    let formTemp: any = {
        selectedCompany: new FormControl(null, [Validators.required]),
    }
    
    this.addForm = this._formBuilder.group(formTemp);
    

    First time addForm is initialized all is good. But when i reopen modal where form is located, and same component code is executed, above mentioned error occurs.

  • Mario Petrovic
    Mario Petrovic almost 6 years
    Yea, for your use case with reactive forms solution.
  • Joshua Kemmerer
    Joshua Kemmerer about 5 years
    You can also use [FormGroup].patchvalue(object) if you only want to update a select number of properties/form controls
  • Frankie Drake
    Frankie Drake about 4 years
    Mario, thank you so much for this solution, this is much better then @zucker's answer (btw offered by all others), also I believe this solution should be considered as a default form creation in general.
  • Jimmy Kane
    Jimmy Kane almost 4 years
    That's what worked for me with the new DateRange and Angular material. Thanks