To destroy the subscription used in the component manually is a tedious task, so in order to solve this issue a solution is provided which automatically unsubscribes the subscription as soon as the component is destroyed.
In Angular 16, we were introduced to a new method called takeUntilDestroyed(). This method completes the Observable when the calling context (component, directive, service, etc) is destroyed.
import { Component } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; @Component({ selector: "my-component", templateUrl: "./my-component.html", styleUrls: ["./my-component.scss"] }) export class MyComponent { constructor(private http: HttpClient) { this.http.get('/api').pipe(takeUntilDestroyed()).subscribe(); } }
NOTE: If you are trying to do the same outside of the constructor you may see this error takeUntilDestroyed() can only be used within an injection context such as a constructor To fix this update to the following
import { Component, DestroyRef, OnInit, inject } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; @Component({ selector: "my-component", templateUrl: "./my-component.html", styleUrls: ["./my-component.scss"] }) export class MyComponent implements OnInit { destroyedRef = inject(DestroyRef); ngOnInit(): void { this.http.get('/api').pipe(takeUntilDestroyed(this.destroyedRef)).subscribe(); } }
In this version, we only had the takeUntil() method, so we had to rely on a subject variable in order to store the reference for the subscription.
Note the use of the pipe() method.
class myComponent { private destroyed$: ReplaySubject= new ReplaySubject(1); constructor( private serviceA: ServiceA, private serviceB: ServiceB, private serviceC: ServiceC) {} ngOnInit() { this.serviceA .pipe(takeUntil(this.destroyed$)) .subscribe(...); this.serviceB .pipe(takeUntil(this.destroyed$)) .subscribe(...); this.serviceC .pipe(takeUntil(this.destroyed$)) .subscribe(...); } ngOnDestroy() { this.destroyed$.next(true); this.destroyed$.complete(); } }
class myComponentOld { private destroyed$: ReplaySubject= new ReplaySubject(1); constructor(private serviceA: ServiceA) {} ngOnInit() { this.serviceA .takeUntil(this.destroyed$) .subscribe(...); } ngOnDestroy() { this.destroyed$.next(true); this.destroyed$.complete(); } }