DEV Community

Cover image for The Only 2 Ways, You Ever Need To Unsubscribe Angular Observables
Dev By RayRay
Dev By RayRay

Posted on • Originally published at hasnode.byrayray.dev

The Only 2 Ways, You Ever Need To Unsubscribe Angular Observables

Clean Up Angular Observables In An Easy Way

Angular is full of Observables. But is there is a mechanism that automatically unsubscribes your Observables when components get destroyed?

I've read a ton of different posts about cleaning your subscriptions. There are so many different ways, but I missed that one post that showed me how you should handle your subscriptions and when.

To prevent you from reading all these posts like me, here is a practical post explaining how to unsubscribe from your Observables easily.

divider-byrayray.png

TLDR;

The short version, for those who don't want to dive into it 😅. Here are the solutions.

Async Pipe

| async the async pipe offers you to handle Observables in your HTML template. The async pipe automatically runs the unsubscribe process after the destruction process of a component.

takeUntil

takeUntil can be called in the .pipe() method before you subscribe. With this method, you can add your subscription to a Subject. If you have a few subscriptions in it, you can unsubscribe it in the ngOnDestroy event with the .next() and .complete() methods.

divider-byrayray.png

1. Observables In A HTML Template With Async Pipe

Angular offers a simple way to handle your Observables in the HTML template via the async pipe | async . The best thing is, Angular takes the unsubscribe process for you instead of doing it yourself.

You can use the async pipe for singular values.

@Component({
    selector: 'cool-component',
    template: `
        <h1>{{pageTitle$ | async}}</h1>
    `
    ...
})
export class CoolComponent implements OnInit {
    private pageTitle$: Observable<string>;

    constructor(private httpService: HttpClient) {}

    ngOninit(): void {
        this.pageTitle$ = this.httpService.get('some-url.com')
    }
}
Enter fullscreen mode Exit fullscreen mode

Or you can use it for values that are Objects or Arrays.

@Component({
    selector: 'cool-component',
    template: `
        <ul>
            <li *ngFor="let item of todoList$ | async">{{item.name}}</li>
        </ul>
    `
    ...
})
export class CoolComponent implements OnInit {
    private todoList$: Observable<string>;

    constructor(private httpService: HttpClient) {}

    ngOninit(): void {
        this.todoList$ = this.httpService.get('other-url.com')
    }
}
Enter fullscreen mode Exit fullscreen mode

So in this component, you don't need to trigger something with the ngOnDestroy , but it automatically will unsubscribe to the subscriptions during the destruction process of the component.

divider-byrayray.png

If you want to learn more about the Async pipe in Angular, check out this post "Angular and RxJS: A deep dive into async pipe" by Erxk

divider-byrayray.png

2. Observables With takeUntil method

Let's say you are making multiple AJAX request via the HttpClient. You're not going to pass it directly to the HTML, but doing something else with the data first. So the | async pipe is not ideal for this situation.

Now you have multiple subscriptions!

How can we unsubscribe them all at once instead of unsubscribing them one by one?

First, we have to make a Subject in our component.

@Component({...})
export class CoolComponent {
    private unsubscribe$ = new Subject<void>;
}
Enter fullscreen mode Exit fullscreen mode

This Subject is going to be used to store our subscriptions.

Now let's make some subscriptions in our ngOnInit with the HttpClient.

@Component({...})
export class CoolComponent implements OnInit {
    private unsubscribe$ = new Subject<void>;

constructor(private httpService: HttpClient) {}

    ngOninit(): void {
        this.httpService.get('some-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })

        this.httpService.get('other-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, after the get() method there is a pipe(takeUntil(this.unsubscribe$)). With the takeUntil we add a reference from this Observable to the unsubscribe$ Subject.

The Subject holds references to both Observables during the subscription process.

@Component({...})
export class CoolComponent implements OnInit, OnDestroy {
    private unsubscribe$ = new Subject<void>;

    constructor(private httpService: HttpClient) {}

    ngOninit(): void {
        this.httpService.get('some-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })

        this.httpService.get('other-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })
    }

    ngOnDestroy(): void {
        this.unsubscribe$.next();
        this.unsubscribe$.complete();
    }
}

Enter fullscreen mode Exit fullscreen mode

The ngOnDestroy() method is called before a component is going to be destroyed.

In this method, we call two methods.

The next() will pass an empty value to the subscription. With the complete(), we tell the subscription it's done listening for new values.

Now we don't have to worry about making one or a lot more requests via the HttpClient; we can stop them all at once.

Be careful with this method that you don't forget to add the ngOnDestroy method to your component. We are humans, so we forget them.

divider-byrayray.png

Conclusion

These two strategies will be usable in nine out of ten situations, so a great plan to implement in your Angular applications.

If you have other ideas on how to handle your Observables in an Angular application in a simple way, please let me know 😉

divider-byrayray.png

Thanks!

hashnode-footer.png
*I hope you learned something new or are inspired to create something new after reading this story! 🤗 If so, consider subscribing via email (scroll to the top of this page) or follow me here on Hashnode.
*

Did you know that you can create a Developer blog like this one, yourself? It's entirely for free. 👍💰🎉🥳🔥

If I left you with questions or something to say as a response, scroll down and type me a message. Please send me a DM on Twitter @DevByRayRay when you want to keep it private. My DM's are always open 😁

Discussion (2)

Collapse
jurrievoss profile image
Jurjen Vos

Nice article!

Question though:
what happens when you use multiple async pipes in your html template with the same api call? Will it trigger multiple requests?

Collapse
devbyrayray profile image
Dev By RayRay Author

As long as you refer to the same Observable, you will have 1 API call and multiple places where your results are shown 😉