Cannot read properties of undefined (reading 'get') at get xyzArray [as xyzArray] Angular 14

888 Views Asked by At

I'm trying to implement FormArray into my project to generate dynamic FormControls.But I'm stuck at this error which I'm not able to understand.Whenever I create a getter method to get my array from FormGroup this error pops up.I'm going to explain the error with all the details....

Error in Console

enter image description here

When I click at the line pointed with RED ARROW IN ABOVE IMAGE it takes me to this following line of code and points at let data = await lastValueFrom(res);

 public async getScheduleData(): Promise<SchemaSchedule> {
let res = this.http.get<SchemaSchedule>(`${this.host}/api/demo-schedule`);
let data = await lastValueFrom(res);
return data;

}

When I click at the line pointed with BLUE ARROW IN ABOVE IMAGE it takes me to this following line of code and points at dayForm.get

 get mondayArray(): FormArray {
        return this.dayForm.get('mondayArray') as FormArray;
      }

Detailed Code Related to Above Error in TS file

async ngOnInit() {
    this.scheduleResult = await this.service.getScheduleData();
    this.setDay(
      this.scheduleResult.monday![0]
    );

  }
  async setDay(d1: Duration) {
    this.dayForm = new FormGroup({
      mondayArray: new FormArray([
        new FormGroup({
          startTime: new FormControl(d1.startTime),
          endTime: new FormControl(d1.endTime),
        }),

      ]),
    });
  }
  get mondayArray(): FormArray {
    return this.dayForm.get('mondayArray') as FormArray;
  }

When I click at the line pointed with YELLOW ARROW IN ABOVE IMAGE it takes me to this following line of code and points at index as i

<div
        class="loop_class"
        *ngFor="
         let item of mondayArray.controls;
         index as i
          "
          >

Detailed Code Related to Above Error in html file

<div class="formArray" formArrayName="mondayArray">
                          <div
                            class="loop_class"
                            *ngFor="
                              let item of mondayArray.controls;
                              index as i
                            "
                          >
                            <div class="dynamic_Forms" [formGroupName]="i">
                              <div class="from">
                                <select
                                  name="from"
                                  id="a"
                                  class="text-sm rounded-lg focus:border-primary border border-[#BCBCBC] py-[10px] px-4 focus:outline-none"
                                  formControlName="startTime"
                                  [ngClass]="monState ? '' : 'hidden'"
                                >
                                  <option
                                    [value]="timing.value"
                                    *ngFor="let timing of timingStart"
                                    selected="{{ timing.selected }}"
                                  >
                                    {{ timing.time }}
                                  </option>
                                </select>
                              </div>
                              <div class="divider">
                                <img src="/assets/icons/add.svg" alt="" />
                              </div>
                              <div class="to">
                                <select
                                  name="to"
                                  class="text-sm rounded-lg focus:border-primary border border-[#BCBCBC] py-[10px] px-4 focus:outline-none"
                                  formControlName="endTime"
                                >
                                  <option
                                    [value]="timing.value"
                                    *ngFor="let timing of timingEnd"
                                    selected="{{ timing.selected }}"
                                  >
                                    {{ timing.time }}
                                  </option>
                                </select>
                              </div>
                            </div>
                          </div>
                        </div>
2

There are 2 best solutions below

7
nate-kumar On

As dayForm is only instantiated after the response from an asynchronous http call (this.http.get<SchemaSchedule>('${this.host}/api/demo-schedule') which triggers setDay()), this means that from the component's initalisation until the GET call completes, dayForm may be undefined. It therefore helpful to think of dayForm's actual type as FormGroup | undefined

This then leads us to understand that if the getter is trying to access the form control 'mondayArray' but dayForm is undefined, an error will be thrown as the 'mondayArray' key is missing.

There are a couple of ways we could protect for this, both are valid depending on the use case

  1. Modify the mondayArray getter to correctly reflect that mondayArray will either be a FormArray or undefined. This will mean that you will have to null check mondayArray whenever you want to access any information on it (as it could be undefined)
get mondayArray(): FormArray | undefined {
  if (!this.dayForm) return undefined;
  return this.dayForm.get('mondayArray') as FormArray
}
  1. Force the getter to always return an array to satisfy typing mondayArray as FormArray. This means during initialisation, any code which needs to access mondayArray will be fed an empty array ([]) instead.
get mondayArray(): FormArray {
  return (this.dayForm?.get('mondayArray') || []) as FormArray;
}

If there are still errors after making one of these changes, you could try simplifying by using observables instead of async/await

service.ts

public getScheduleData$(): Observable<SchemaSchedule> {
  return this.http.get<SchemaSchedule>(`${this.host}/api/demo-schedule`);
}

component.ts

ngOnInit() {
  this.service.getScheduleData$()
    .subscribe(
      scheduleData => {
       this.setDay(this.scheduleData.monday[0]);
      }
    )
}

setDay(d1: Duration) {
  this.dayForm =
    new FormGroup({
      mondayArray: new FormArray([
        new FormGroup({
          startTime: new FormControl(d1.startTime),
          endTime: new FormControl(d1.endTime),
        }),
      ]),
    });
}
0
M Nouman On

The issue in my case was that the array was empty at backend. And Angular was receiving nothing in GET from api that's why it was giving the error due to empty get. When I put some data using swagger at the backend the issue resolved.