Unsubscribing from Observables in Angular

You’ve probably heard a lot about RxJs, and more than likely used it in your Angular applications. If so, have you learned how to unsubscribe from observables? Do you know why it is important to do so? Not doing so ended up biting me in the butt. Read ahead for several simple ways on how you can properly unsubscribe from observables! You can also see these techniques in action here in this Stackblitz project.

Why is this important?

ngOnInit() {
this.observable.subscribe((value) => {
// important logic on app state, modification of DOM, etc.
});
}

What happens to this observable when the component is no longer rendered in the DOM? If the observable is fired, will the code here still run? The answer is, yes, it does. If this observable triggers logic like manipulating the DOM, you might see errors when the code tries accessing HTML elements that are no longer rendered. If it triggers business logic, you might see incorrect data throughout the application. That is extremely difficult to debug, and what makes unsubscribing from observables so important. You can see in the gif below that the observable continues to fire, even after the component has been removed from the DOM.

We can fix this issue using any of the following examples!

unsubscribe()

this.someObservable = interval(1000).subscribe((value) => {
console.log('value: ', value);
});

It fires a number, starting from 0, and increases by an increment of 1 every second. In order to unsubscribe from this observable we can simply call unsubscribe() on the observable in ngOnDestroy. Why in ngOnDestroy? That is the lifecycle hook that gets fired when the component is being destroyed.

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

take(n)

this.someObservable = interval(1000).pipe(take(5))
.subscribe((value) => {
console.log('value: ', value);
});

Using this technique we don’t need to call unsubscribe() in ngOnDestroy. I should caution you, however, to ensure you choose a number of times you know the observable will fire. If there is no guarantee, you should unsubscribe as we did in the first example in order to properly clean up the observable, in case it does not fire that many times.

takeUntil(x)

private unsubscribe: Subject<any> = new Subject<any>();

Make sure the unsubscribe subject is private so it can’t be accessed outside of this component. Using a variation of the previous observables, we will directly subscribe to the observables and not set them to a variable in the component. The first is fired every half second and the second is fired every second. You will see that we are making use of the unsubscribe subject by passing it to the takeUntil operator. Here are the observables we are subscribed to:

interval(500).pipe(takeUntil(this.unsubscribe))
.subscribe((value) => {
console.log('observable 1: ', value);
});
interval(1000).pipe(takeUntil(this.unsubscribe))
.subscribe((value) => {
console.log('observable 2: ', value);
});

To unsubscribe from both of these observables at once when the component is destroyed, in ngOnDestroy we simply call next() with no value and complete() to complete the subject.

ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}

Final Thoughts

You can find me on Twitter, GitHub, LinkedIn, and my website!

Full-stack software engineer specializing in web and mobile development. Always learning new things. “There is no growth in the comfort zone…”