Reputation: 8352
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.
Upvotes: 26
Views: 14664
Reputation: 4310
I found a weird "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.
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
.
Upvotes: 3
Reputation: 1112
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
.
Upvotes: 19
Reputation: 8352
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.
Upvotes: 29