I typically review a fair amount of Angular code at work. One thing I typically encourage is using plain Observable s in an Angular Component, and using AsyncPipe ( foo | async ) from the template html to handle subscription, rather than directly subscribing to an observable in a component TS file.

Subscribing in Components

Unless you know a subscription you’re starting in a component is very finite (e.g. an HTTP request with no retry logic, etc), subscriptions you make in a Component must:

Be closed, stopped, or cancelled when exiting a component (e.g. when navigating away from a page), Only be opened (subscribed) when a component is actually loaded/visible (i.e. in ngOnInit rather than in a constructor).

Consider:

@ Component ( ) export class Foo implements OnInit , OnDestroy { someStringToDisplay = '' ; private readonly onDestroy = new ReplaySubject < void > ( 1 ) ; ngOnInit ( ) { someObservable . pipe ( takeUntil ( this . onDestroy ) , map ( ... ) , ) . subscribe ( next => { this . someStringToDisplay = next ; this . ref . markForCheck ( ) ; } ) ; } ngOnDestroy ( ) { this . onDestroy . next ( undefined ) ; } } @ Component ( ) export class Foo implements OnInit , OnDestroy { someStringToDisplay = '' ; private subscription = Subscription . EMPTY ; ngOnInit ( ) { this . subscription = someObservable . pipe ( map ( ... ) , ) . subscribe ( next => { this . someStringToDisplay = next ; this . ref . markForCheck ( ) ; } ) ; } ngOnDestroy ( ) { this . subscription . unsubscribe ( ) ; } }

< span > {{someStringToDisplay}} </ span >

AsyncPipe can take care of that for you

@ Component ( ) export class Foo { someStringToDisplay = someObservable . pipe ( map ( ... ) , ) ; }

< span > {{someStringToDisplay | async}} </ span >

Much better! No need to remember to manage unsubscribe. No need to implement OnDestroy . AsyncPipe does its own unsubscribe on destruction, etc. If you only implement OnInit to make a new subscription, you can forego that too.

Best Practice: Use publishReplay and refCount if accessing the same Observable from multiple places

If you need to access a value multiple times, consider using the publishReplay and refCount RxJS operators:

readonly pageTitle = this . route . params . pipe ( map ( params => params [ 'id' ] ) , flatMap ( id => this . http . get ( ` api/pages/ ${ id } /title ` , { 'responseType' : 'text' } ) ) , publishReplay ( 1 ) , refCount ( ) ) ;

< h1 > {{pageTitle | async}} </ h1 > < p > You are viewing {{pageTitle | async}}. </ p >

This will cause the template rendering to make a single request for pageTitle , and cache the result between both uses.

Best Practice: Combine *ngIf , as , and else with AsyncPipe

If you need to handle the loading state, and need to display nested properties of an object returned from an observable, you can do something like:

< ng-container *ngIf = " (pageObservable | async) as page; else loading " > < h1 > {{page.title}} </ h1 > < p > {{page.paragraph}} </ p > </ ng-container > < ng-template #loading > Loading… </ ng-template >