Angular 4+ ngOnDestroy() in service - destroy observable
Just to clarify - you don't need to destroy Observables
but only the subscriptions made to them.
It seems like others have pointed out that you are now able to use ngOnDestroy
with services as well. Link: https://angular.io/api/core/OnDestroy
OnDestroy lifecycle hook is available in providers. According to the docs:
Lifecycle hook that is called when a directive, pipe or service is destroyed.
Here's an example:
@Injectable()
class Service implements OnDestroy {
ngOnDestroy() {
console.log('Service destroy')
}
}
@Component({
selector: 'foo',
template: `foo`,
providers: [Service]
})
export class Foo implements OnDestroy {
constructor(service: Service) {}
ngOnDestroy() {
console.log('foo destroy')
}
}
@Component({
selector: 'my-app',
template: `<foo *ngIf="isFoo"></foo>`,
})
export class App {
isFoo = true;
constructor() {
setTimeout(() => {
this.isFoo = false;
}, 1000)
}
}
Notice that in the code above Service
is an instance that belongs to Foo
component, so it can be destroyed when Foo
is destroyed.
For providers that belong to root injector this will happen on application destroy, this is helpful to avoid memory leaks with multiple bootstraps, i.e. in tests.
When a provider from parent injector is subscribed in child component, it won't be destroyed on component destroy, this is component's responsibility to unsubscribe in component ngOnDestroy
(as another answer explains).
Create a variable in your service
subscriptions: Subscriptions[]=[];
Push each of your subscribe to the array as
this.subscriptions.push(...)
Write a dispose()
method
dispose(){
this.subscriptions.forEach(subscription =>subscription.unsubscribe())
Call this method from your component during ngOnDestroy
ngOnDestroy(){
this.service.dispose();
}
I prefer this takeUntil(onDestroy$)
pattern enabled by pipable operators. I like that this pattern is more concise, more clean, and it clearly conveys the intent to kill a subscription upon execution of the OnDestroy
lifecycle hook.
This pattern works for services as well as components subscribing to injected observables. The skeleton code below should give you enough detail to integrate the pattern into your own service. Imagine you're importing a service called InjectedService
...
import { InjectedService } from 'where/it/lives';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MyService implements OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(
private injectedService: InjectedService
) {
// Subscribe to service, and automatically unsubscribe upon `ngOnDestroy`
this.injectedService.observableThing().pipe(
takeUntil(this.onDestroy$)
).subscribe(latestTask => {
if (latestTask) {
this.initializeDraftAllocations();
}
});
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
The topic of when/how to unsubscribe is covered extensively here: Angular/RxJs When should I unsubscribe from `Subscription`