58

I have created this interface:

interface IGame {
    name: string;
    description: string;
}

I'm using it as an Observable and passing it as Input to the Component:

@Input() public game: Observable<IGame>;

I can see its value printed using the JSON pipe:

 <h3>{{game | json}}</h3>

When binding to a specific property, nothing is displayed (just an empty string):

 <h3>{{game.name}}</h3>
 <h3>{{game.description}}</h3>
Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
Lior Kooznits
  • 623
  • 1
  • 5
  • 6

3 Answers3

84

The async pipe does the subscription in view bindings

 <h3>{{(game | async)?.name}}</h3>

The ? is only necessary when null values might be emitted.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
22

Shortcut for binding multiple properties

Using the *ngIf-As-Syntax factors out the async pipe into a single call (and a single subscription).

  <ng-container *ngIf="( game$ | async ) as game">
    <h3>{{ game.name }}</h3>
    <h3>{{ game.description }}</h3>
  </ng-container>

This only creates one subscription to the observable, it removes the need for ?. and makes working with the template much cleaner.

Note: I renamed the original example observable from game to game$.

Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
Florian
  • 451
  • 3
  • 13
  • 1
    This answer provides slightly better user experience than the other one as it renders `

    {{ game.name }}

    ` and `

    {{ game.description }}

    ` at the same time.
    – Random Tourist Mar 16 '20 at 15:11
  • 1
    hmm... i was thinking about your comment... it does render both fields at the same time - but if game$ is false it doesn't render anything at all - while the above example still renders the empty html-elements... So it differs - maybe causing problems when you maybe use a marker on these elements – Florian Mar 17 '20 at 09:45
4

The modern solution: *ngrxLet

NgRx 10 presented the @ngrx/component package with the *ngrxLet directive - a convenient way to bind observables in templates.

Usage example:

<ng-container *ngrxLet="observableNumber$ as n">
    <app-number [number]="n"></app-number>
</ng-container>

You can even track all the observable notifications:

<ng-container *ngrxLet="observableNumber$; let n; let e = $error, let c = $complete">
    ....
</ng-container>

From the NgRx docs:

The current way of binding an observable to the view looks like that: *ngIf="observableNumber$ | async as n". The problem is *ngIf is also interfering with rendering and in case of a falsy value the component would be hidden. The *ngrxLet directive takes over several things while making it more convenient and safe to work with streams in the template.

An explanatory tutorial about ngrxLet can be found here.

Shaya
  • 2,792
  • 3
  • 26
  • 35