Custom component FormControl breaking if reinitializing FormGroup from parent

Viewed 11783

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.

3 Answers

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.

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.

Related