Unsubscribe Angular Observable

The component will get destroyed but the subscription will live on. So unsubscribed observable may create a memory leak.

The .unsubscribe() Method

@Component({...})
export class CustomComponent implements OnInit, OnDestroy {
    sub1: Subscription;
    sub2: Subscription;

    constructor(private httpClient: HttpClient) {}

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

    ngOnDestroy(): void {
        this.sub1?.unsubscribe();
        this.sub2?.unsubscribe();
    }
}

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.

@Component({
    selector: 'custom-component',
    template: `
        <h1>{{pageTitle$ | async}}</h1>
    `
    ...
})
export class CustomComponent implements OnInit {
    pageTitle$: Observable<string>;
    constructor(private httpClient: HttpClient) {}
    ngOninit(): void {
        this.pageTitle$ = this.httpClient.get('custom-url.com')
    }
}

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

@Component({
    selector: 'custom-component',
    template: `
        <ul>
            <li *ngFor="let item of todoList$ | async">{{item?.name}}</li>
        </ul>
    `
    ...
})
export class CustomComponent implements OnInit {
    todoList$: Observable<string>;
    constructor(private httpClient: HttpClient) {}
    ngOninit(): void {
        this.todoList$ = this.httpClient.get('other-url.com')
    }
}

Or you can reuse async value.

@Component({
    selector: 'custom-component',
    template: `
        <ng-contatine *ngIf="data$ | async as data">
            {{ data?.title }}
            <div *ngFor="let item of data?.list">{{ item?.name }}</div>
        </ng-contatine>
    `
    ...
})
export class CustomComponent implements OnInit {
    data$: Observable<string>;
    constructor(private httpClient: HttpClient) {}
    ngOninit(): void {
        this.data$ = this.httpClient.get('url.com')
    }
}

Advanced way:

{{ (data$ | async)?.title }}

Observables With takeUntil Method

@Component({...})
export class CustomComponent implements OnInit, OnDestroy {
    unsubscribe$ = new Subject<void>();
    constructor(private httpClient: HttpClient) {}

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

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

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.

Sources:

Leave a Comment