Brian Love
Angular + TypeScript Developer in Denver, CO

Angular: Don't forget to unsubscribe()

Reading time ~3 minutes

Don’t forget to unsubscribe from subscriptions in Angular components using the OnDestroy lifecycle hook. We’ll look at:

  1. Why you need to unsubscribe
  2. When you likely should unsubscribe
  3. How you unsubscribe

Updated January 4, 2017

I have updated this post to include the use of the takeWhile() operator as a better strategy for unsubscribing in your Angular components.

Why?

Reactive-Extensions for JavaScript (or RxJS) introduces the concept of Observables to Angular. If you have been using version 1 of Angular then you are likely comfortable using Promises. And, while you might think that an Observable is just like a Promise you might be surprised (as I was) to learn that they are in fact very different.

First, Promises are eager and are executed immediately. Observables are not eager and are only executed when subscribed to.

Second, Promises are asynchronous. Observables can be either synchronous or asynchronous.

Third, Promises are expected to return only a single value (like a function). Observables can return zero, one or more (infinitely) values.

Let me get to the point. A subscription is created when we subscribe() to an observable. And it is important that we unsubscribe from any subscriptions that we create in our Angular components to avoid memory leaks.

AsyncPipe

Before we go any farther; if you are using observable streams via the AsyncPipe then you do not need to worry about unsubscribing. The async pipe will take care of subscribing and unsubscribing for you.

When?

Ok, we covered the why - but, when do we unsubscribe? In most instances the best time to unsubscribe is when your component is destroyed. Angular 2 introduced the the ngOnDestroy() lifecycle method:

ngOnDestroy(): Cleanup just before Angular destroys the directive/component. Unsubscribe observables and detach event handlers to avoid memory leaks.

How?

There are two common approaches:

  1. Store the subscription and invoke the unsubscribe() method when the component is destroyed.
  2. Use the takeWhile() operator to trigger the unsubscription.

unsubscribe()

First, let’s assume we have a UserService class with an authenticate() method:

@Injectable()
export class UserService {

  public authenticate(email: string, password: string): Observable<User> {
    //code omitted
  }
}

In our component we first import the OnDestroy class from @angular/core as well as the ISubscription interface from rxjs:

import { OnDestroy } from "@angular/core";
import { ISubscription } from "rxjs/Subscription";

Next, we implement the abstract class and declare a variable to store a reference to our subscription:

export class MyComponent implements OnDestroy {

  private subscription: ISubscription;

}

Next, let’s subscribe to the observable returned from the UserService.authenticate() method. In this example I have a method that is invoked when a login form is submitted:

public onSubmit() {
  //authenticate the user via the UserService
  this.subscription = this.userService.authenticate(email, password).subscribe(user => {
    this.user = user;
  });
}

Finally, when our component is destroyed we unsubscribe:

ngOnDestroy() {
  this.subscription.unsubscribe();
}

takeWhile()

Note that we were previously storing a single subscription in a private variable named subscription. If you have multiple subscriptions in your component you could store all of your subscriptions in a collection, and then unsubscribe from each when the component is destroyed. However, there is a better way.

The takeWhile() operator to the rescue:

The TakeWhile mirrors the source Observable until such time as some condition you specify becomes false, at which point TakeWhile stops mirroring the source Observable and terminates its own Observable.

First, we need to import the takeWhile() operator:

import "rxjs/add/operator/takeWhile";

Then, let’s use the takeWhile() operator with our observable that is returned from UserService.authenticate():

export class MyComponent implements OnDestroy, OnInit {

  public user: User;
  private alive: boolean = true;

  public ngOnInit() {
    this.userService.authenticate(email, password)
      .takeWhile(() => this.alive)
      .subscribe(user => {
        this.user = user;
      });
  }

  public ngOnDestroy() {
    this.alive = false;
  }

}

First, I defined a private boolean variable named alive that is set to true. Next, we provide a function to the takeWhile() operator that returns the boolean value (that is initially true). Finally, we set the value of alive to false when the component is destroyed.

As you can see, the takeWhile() operator is an excellent solution to unsubscribing from an observable subscription as part of Angular’s component lifecycle.

Brian Love

Hi, I'm Brian. I am interested in TypeScript, Angular and Node.js. I'm married to my best friend Bonnie, I live in Denver and I ski (a lot).