Form controls not initializing correctly when placed inside a subscribe method in angular

Viewed 276

I'm building an angular app that calls a service to obtain some data then use this data to initialize form controls:

ts:

    form: FormGroup;
    data: any;

    ngOnInit(): void {
        this.service.getData().subscribe((data) => {
            this.data = data;
            this.form = new FormGroup({
                input1: new FormControl(this.data?.data1),
                input2: new FormControl(this.data?.data2)
            });
        });
    }

html:

<form [formGroup]="form">
   <input type="text" formControlName="input1"/>
   <input type="text" formControlName="input2"/>
   <button id="btn" [disabled]="!form.valid"/>
</form>

I get the following error in the browser console when i launch the app:

ERROR TypeError: Cannot read property 'valid' of undefined

It seems like the form controls are not initialized in time when placed inside the subscribe method in ngOnInit. The html is trying to read form.valid when form is not initialized yet. When i try to initialize the form controls outside the subscribe method, i don't get this error but doing it that way won't allow me to access the data from the service.

So my question is, how do i load the data from my service then initialize my form controls using the data i obtained without getting this error?

Thank you in advance!

2 Answers

form will be undefined before you receive a successful response from your backend, you should use the is the safe navigation operator .? like this :

 [disabled]="!form?.valid"

what this does basically is this

if( form != null && form != undefined) { disabled = form.valid ;}
// otherwize disabled = undefined which is falsy

Alternatively, you could enclose your form into a div with a check condition that ensures the data is initialized. For usability purposes, you could show a progress spinner until you get the data.

<div *ngIf="data">
   <form [formGroup]="form">
     <input type="text" formControlName="input1"/>
     <input type="text" formControlName="input2"/>
     <button id="btn" [disabled]="!form.valid"/>
   </form>
 </div>
Related