Observables and the async pipe in Angular

In my previous post about Angular subscription management we concluded that the best solution is to use the async pipe. In this post we’ll see a common problem many people ran into with the async pipe.

An observable intro

Before we dive into the details it’s important to make some observations about observables. Observables are functions that tie together a source (e.g. an HTTP request, an event stream) and an observer (your run-of-the-mill Angular component).

The most important aspect of an observable is its temperature. It can either be cold or hot. A cold observable creates its own source, while a hot observable wraps around one.

Cold observables are creating their sources

Consider the following code:

Notice how the observable is creating and dispatching the XMLHTTPRequest. Every subscriber will get a different request, resulting in multiple calls. We’ll review hot observables and then see how to avoid these issues.

Hot observables are wrapping around an existing source

Hot observables are great in the sense that they can share their results with multiple subscribers (they are multicast). However since they are not owning their source they cannot be lazy. Let’s review the same code fragment with a hot observable:

The hot observable is stored in the subject variable. Note that it wraps around our XMLHTTPRequest, which is completely independent from it. The request will always be sent with or without any subscribers.

Note that this is just for presentational purposes. There are better ways to connect subjects with observables. Also, you’d rarely send raw XMLHTTPRequests in Angular, you’d use the built-in HttpClient instead.

Smart usage of the async pipe

After some theoretical background, let’s see how this affects us and our components.

Look at the below component and template code:

callResult$ is a cold observable and we’re in big trouble. The *ngFor directive will trigger one execution, then the expression with the length below will trigger another.

We can fix this with a hot observable like this:

But this is more code, and we don’t like to write and maintain more code. Let’s try a different approach. A better solution would be this:

Using the async pipe with the async as syntax we can define a template variable. It’s called result in our case. The template then can reuse this variable without triggering the observable multiple times. We made our template code agnostic on the temperature of our observable, yayy!

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practicesFollow this link to the relevant part of the code.

RXJS subscription management in Angular

If you’re reading this then you’re probably familiar with the fact that Angular uses RxJS and embraces the reactive paradigm. You might be familiar that RxJS is based on the Observable class. Let’s recap what this means.
To extract any information from an Observable we need to subscribe to it. A subscription is a bunch of optional callback functions. We can define a success, an error function and a completed function, all of them optional. When an Observable emits, RxJS invokes the proper callback function.
Subscriptions aren’t free though, you’re required to tell RxJS when you’re done with them. It’s pretty easy, you need to invoke their unsubscribe function. The problem is – when and how to do that?

Not unsubscribing

 The easiest – and worst – solution is to ignore the problem. Subscribe to an Observable and leave it at that. When Angular destroys your component the open subscription will simply leak it.
Your subscriptions are holding a reference to the hosting component. If you don’t unsubscribe then you’ll create a memory leak with your whole component.

Manual subscription management

Let’s take a step in the right direction. Usually you’ll set up your observables in the ngOnInit lifecycle hook. There’s a corresponding hook when your component is destroyed, called ngOnDestroy. By simply storing all your subscriptions as members of your component class you can just call unsubscribe on all of them in the destroy hook.
This is a solution to the problem, but not a great one. For simple components it might work. But when you are adding more subscriptions later, you might forget to unsubscribe from them. And let’s face it, we just copying and pasting the code lines in cases like this, and will forget to change the variable name eventually.

Semi-automatic management with takeUntil

 We can harness the power of hot observables, aka Subjects. The logic is the same as when you’re using manual management. The difference is that you create a subject. In every observable subscription you pipe your subject through the takeUntil operator.
You also create an ngOnDestroy hook and complete your subject there. This will unsubscribe from your observables.
There’s a slight catch though. Order matters when piping operators, and you generally want to put takeUntil to the very end. The actual reasons are beyond the scope of this post, refer to this article on Angular in Depth.

Using the async pipe

 My personal favourite is to delegate the subscription management to Angular. This results in much less code and very straightforward components. Angular has the built-in async pipe for consuming observables. You’d use them in your component template.
Notice how all the subscription boilerplate code is gone. That’s a great thing, we need to maintain less code!
Also, when your component is destroyed Angular automatically unsubscribes from your observables. Though there are some caveats you should look out for.
If you use an async pipe multiple times on the same observable you’d get a different subscription. This could lead to multiple API calls. Fixing this will be the subject – pun intended – of my next post.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.