Thomas Segato
Thomas Segato

Reputation: 5223

ngFor for delayed data

I have a component that takes the URL param, call API and displays the data. Most basic and typically sample:

ngOnInit() {
    this.route.params.subscribe( params => { 
      const id = params.id;     
      this.loadAssets(id);
    });
  }

  loadAssets(id)
  {   
    this.apiService.getAssetGroup(id).subscribe((data) => {
      this.assetGroup  =  data;   
      this.assetSubGroupList = data.assetSubGroupList;
      console.log(this.assetGroup);
    });
  }

In my html i do a simple loop:

<div class="row">
    <div class="col-sm-12 col-lg-12">
        <div *ngFor="let subGroup of assetGroup.assetSubGroupList">
            <div>SubGroup: {{subGroup.name}}</div>
            <div *ngFor="let asset of subGroup.assetList">Asset: {{asset.name}}</div>
        </div>
    </div>
</div>

I guess this is some of to most common scenarios in web development. However, I get the following error:

Cannot read property 'assetSubGroupList' of undefined at Object.eval [as updateDirectives] (AssetsComponent.html:5)

My best guess is this is because when the page is loaded assetGroup is null. The page actually ends working after the data is loaded, but i dont want the first error. I am thinking there must be some standard way of handling this scenario in Angular. Do you always initialize variables, use ngIf or even something smarter?

Upvotes: 2

Views: 593

Answers (3)

SiddAjmera
SiddAjmera

Reputation: 39432

Use an async pipe instead. That way you won't have to take care of unsubcribeing as well which is generally recommended and done to avoid any memory leaks.

Just declare a property in your TS Class named assetGroup$(we ideally suffix a $ sign for a value that might be of type Observable. It's just a code convention that you can read more about here.) and then assign it in the loadAssets function like this:

assetGroup$;
...
loadAssets(id) {
  this.assetGroup$ = this.apiService.getAssetGroup(id);
}

Then in your template code use it like this:

<div class="row">
  <div class="col-sm-12 col-lg-12">
    <div *ngFor="let subGroup of (assetGroup$ | async).assetSubGroupList">
      <div>SubGroup: {{subGroup.name}}</div>
      <div *ngFor="let asset of subGroup.assetList">Asset: {{asset.name}}</div>
    </div>
  </div>
</div>

Upvotes: 1

abdullahkady
abdullahkady

Reputation: 1071

It is the reason indeed, one way, you can just use this line this.assetSubGroupList = data.assetSubGroupList; to iterate through, so <div *ngFor="let subGroup of assetSubGroupList">

Or you can do a check using the ? operator like so

<div *ngFor="let subGroup of assetGroup?.assetSubGroupList">

Upvotes: 1

Franklin Pious
Franklin Pious

Reputation: 3848

Add a ? operator to assetGroup

<div *ngFor="let subGroup of assetGroup?.assetSubGroupList">
            <div>SubGroup: {{subGroup.name}}</div>
            <div *ngFor="let asset of subGroup.assetList">Asset: {{asset.name}}</div>
        </div>

Upvotes: 1

Related Questions