Home > Back-end >  Using Angular Observable : cannot read properties of undefined (reading 'foo')
Using Angular Observable : cannot read properties of undefined (reading 'foo')

Time:05-18

I'm having a service as follow:

  public getDoseVignettes() : Observable<DoseVignetteApi> {
    return this.apollo.watchQuery<Query>({
      query: this.VIGNETTE
    }).valueChanges
      .pipe(
        map(result => {
            return result.data.doseVignettes;
          }
        ));
  }

which returns data as expected.

This service is called as follow:


doseVignetteApi! : DoseVignetteApi;

public ngOnInit(): void {
     this.dataService.getDoseVignettes().subscribe(doseVignetteApi => {
        // console.log("VIGNETTE : "   JSON.stringify(doseVignetteApi)); [1]
        this.doseVignetteApi = doseVignetteApi;
      })
}

The console.log [1] would display these data.

The front code is:

<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="20px" 
     *ngFor="let vignette of this.doseVignetteApi!.vignettes!">
  <mat-card  fxFlex="20">
    <mat-card-title>{{vignette!.aliasDose!}}</mat-card-title>
    <mat-card-content>
      <div *ngFor="let item of vignette!.items!">
        {{item.name}} : {{item!.total}}
      </div>
    </mat-card-content>
  </mat-card>
</div>

The data will display on Chrome, but got the following issue with this code:

On Chrome debugger, got : Cannot read properties of undefined (reading 'vignettes') As a consequence, the some others widgets aren't displayed (???)

Should I return an Observable from the service and use async in *ngFor="let vignette of this.doseVignetteApi!.vignettes!" or is there a way with using subscribeas in the code above ?

EDIT: Solution 1

The recommendation of @MikeOne works: the exclamation mark in the HTML template should have been replaced by a question mark.

EDIT: Solution 2

Following the recommendation of @ZrelliMajdi, got it work as follow:

<ng-container
  *ngIf="doseVignetteApi | async as dataServiceDetails">
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="20px" 
     *ngFor="let vignette of this.dataServiceDetails!.vignettes ">
  <mat-card  fxFlex="20">
    <mat-card-title>{{vignette!.aliasDose!}}</mat-card-title>
    <mat-card-content>
      <div *ngFor="let item of vignette!.items!">
        {{item.aliasVaccine}} : {{item!.totalByAlias}}
      </div>
    </mat-card-content>
  </mat-card>
</div>
</ng-container>
public ngOnInit(): void {
   this.doseVignetteApi = this.dataService.getDoseVignettes();
}

CodePudding user response:

You could subscribe on your observable on html template then consume its data:

<ng-container 
*ngIf="dataService | async as dataServiceDetails">
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="20px" 
     *ngFor="let vignette of dataServiceDetails">
  <mat-card  fxFlex="20">
    <mat-card-title>{{vignette!.aliasDose!}}</mat-card-title>
    <mat-card-content>
      <div *ngFor="let item of vignette!.items!">
        {{item.name}} : {{item!.total}}
      </div>
    </mat-card-content>
  </mat-card>
</div>
</ng-container>
  • Related