Search code examples
javascriptangularasynchronousserviceangular-resolver

Angular Load Async data before component initialization


I have a problem to use data from API Calls: I want to use the retrieved data to set checked in a checkbox, but the component is initialized before the api response and I get some console error:

ERROR TypeError: Cannot read property 'id' of undefined

I test the behaviour with a resolver too, but I have the same problem, even if the response array is logged before initialization:

component.ts

...
export class RolesComponent implements OnInit {

  flag: boolean = false;
  simpleArr: object[] = [
    { userId: 1, id: 2 },
    { userId: 1, id: 3 },
    { userId: 1, id: 5 },
    { userId: 1, id: 7 }
  ]
  permArr: object[] = [];
  permArrResolved: object[] = [];

  levels = [
    { name: 0, description: 'Creazione nuovo utente' },
    { name: 1, description: 'Reset password di qualsiasi utente' },
    { name: 2, description: 'Eliminazione di qualsiasi utente' },
    { name: 3, description: 'Modifica livello di qualsiasi utente' },
    { name: 4, description: 'Rinnovo delle licenze' },
    { name: 5, description: 'Gestione completa delle licenze' },
    { name: 6, description: 'Gestione completa dei clienti' },
    { name: 7, description: 'Gestione completa dei PC' }
  ];

  constructor(private api: RolesApiService, private route: ActivatedRoute, ) {

    this.api.getKeys().subscribe(keys => {
      this.permArr = keys;
      console.log(this.permArr);
      this.flag = true
    });

    this.route.data.pipe(
      map(data => data.cres)).subscribe((key) => {
        this.permArrResolved = key;
        console.log(this.permArrResolved);
      });

  }

  ngOnInit() {
    console.log('component is initialized');
  }

}

component.html

<form *ngIf="flag">
  <h2>with permArr[0].id</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name === permArr[0]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

<hr>

<h2>with simpleArr[level.name].id</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name === simpleArr[level.name]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

<hr>

  <h2>with permArr[level.name].id</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name == permArr[level.name]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

<hr>

  <h2>with permArr[level.name].id using resolver</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name == permArrResolved[level.name]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

</form>

I've made a stackblitz demo to show the error, the api-service, the routing and the resolver I use. is here: https://stackblitz.com/edit/async-angular-resolver

How can I solve this problem?

EDIT: using safe oprators do not solve the bug EDIT2: using *ngIf in form tag do not solve the bug


Solution

  • There are already several answers here that correctly answer the question you are asking - the reason they dont work for you is because the data you are binding does not matching your ids.

    Your previous questions were both basically asking the same thing:

    To prevent further wasted effort from the community, I've gone to the effort of writing the debug code you should be writing yourself. This shows how the safe navigation operator fixes the template issue, as several people have suggested already - wrapping with *ngIf would also solve the problem and the values I've added show why your tick boxes are not checked.

    https://stackblitz.com/edit/async-angular-resolver-hxxyw4?file=src/app/roles/roles.component.html