Search code examples
angularngrxngrx-store

how to use async inside html


How can I include async here in this code for user?

<div *ngIf="usersService.loaded$ | async">
<nb-card>
  <nb-card-header>
    <h1> {{ user?.name }} | {{ user?.age }} </h1>
  </nb-card-header>
</nb-card>

The user is being initiated as follows using a method from the store:

    this.user = this.route.params
      .pipe(
        takeUntil(this.destroyed$),
        switchMap(({ userId }) => this.usersService.getSelectedUser(userId))
      );

Solution

  • Here is one solution:

    <div *ngIf="usersService.loaded$ | async">
        <nb-card>
            <nb-card-header>
                <ng-container *ngIf="user | async as usr; else notFound">
                    <h1>{{usr.name}} | {{usr.age}}</h1>
                </ng-container>
            </nb-card-header>
        </nb-card>
    </div>
    <ng-template #notFound>
        <div class="error">could not locate the user</div>
    </ng-template>
    

    If you want to use the user in other parts of the card, you can move the *ngIf="user | async as usr" to the <nb-card> element. That way the user would be available in any card content.

    <div *ngIf="usersService.loaded$ | async">
        <nb-card *ngIf="user | async as usr; else notFound">
            <nb-card-header>
                <h1>{{usr.name}} | {{usr.age}}</h1>
            </nb-card-header>
            <nb-card-content>
               {{usr.bio}}
            <nb-card-content>
        </nb-card>
    </div>
    <ng-template #notFound>
        <div class="error">could not locate the user</div>
    </ng-template>
    

    In the two cases above, if the user observable's value is null, then the *ngIf will fail. In some cases, you may want to use a default value when the user is null. I have been using this little trick that I probably learned somewhere on SO :)

    <div *ngIf="usersService.loaded$ | async">
        <nb-card *ngIf="{usr: user | async} as obs">
            <nb-card-header>
                <h1>{{obs.usr?.name || 'Jane Doe'}} | {{obs.usr?.age || '100'}}</h1>
            </nb-card-header>
            <nb-card-content>
               {{obs.usr?.bio || 'Very Famous'}}
            <nb-card-content>
        </nb-card>
    </div>
    

    Actually, I would probably join the two observables like this...

    <ng-container *ngIf="{loaded: usersService.loaded$ | async, usr: user | async} as obs">
        <div *ngIf="obs.loaded">
          <nb-card>
              <nb-card-header>
                  <h1>{{obs.usr?.name || 'Jane Doe'}} | {{obs.usr?.age || '100'}}</h1>
              </nb-card-header>
              <nb-card-content>
                {{obs.usr?.bio || 'Very Famous'}}
              <nb-card-content>
          </nb-card>
        </div>
    </ng-container>