DEV Community

Alireza Razinejad
Alireza Razinejad

Posted on

Best practice for subscribing to observables in services with Angular

I do not like to subscribe to observables inside services, as it feels expensive due to the fact that we are not able to unsubscribe from them when we do not need them any more and we all hate memory leaks, right?

So the best way to use this solution will be the way that we would be able to unsubscribe from them when we done listening to that observable.

First, we should not create that service as Singleton service, instead we should make sure the service will be specifically responsible only to handle some functionalities which is related to small part of our app at presentation layer or better to say, it will only take care of logics which related to the Dump component. It does not mean it should not be there for make container/smart components more simple, but in this example I was trying to do it for my Dump component.

Alright, let's say our service is looks like this

import {Injectable, OnDestroy} from '@angular/core';
import {Actions, ofType} from '@ngrx/effects';

import {BehaviorSubject, Observable, Subject} from 'rxjs';
import {takeUntil} from 'rxjs/operators';

import {updateNoteError, updateNoteSuccess} from '../../store/notebook.actions';
import {INote} from '../../interfaces/note.interface';

@Injectable()
export class CreationFacade implements OnDestroy {
  private destroyed$ = new Subject();

  private updateNote$ = new Subject<void>();

  constructor(private actions$: Actions) {
    this.listenToUpdateProcess();
  }

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

  updateStatus(): Observable<void> {
    return this.updateNote$.asObservable();
  }

  private listenToUpdateProcess(): void {
    this.actions$.pipe(
      ofType(updateNoteSuccess),
      takeUntil(this.destroyed$))
      .subscribe(() => {
        this.updateNote$.next()
      });
    this.actions$.pipe(
      ofType(updateNoteError),
      takeUntil(this.destroyed$))
      .subscribe((error) => {
        this.updateNote$.error(error)
      });
  }
}

Enter fullscreen mode Exit fullscreen mode

Have you noticed this line?

@Injectable()
export class CreationFacade implements OnDestroy 
Enter fullscreen mode Exit fullscreen mode

Yes, I've implemented OnDestroy interface to my service and Angular will call this lifecycle only if we provide it to the corresponding component and only there but not in the Module.

So meta data we will pass to to @Component decorator will be like this

@Component({
  selector: 'app-note-writing',
  templateUrl: './note-writing.component.html',
  styleUrls: ['./note-writing.component.scss'],
  providers: [CreationFacade]
})
Enter fullscreen mode Exit fullscreen mode

Isn't that great?

Now we can relax and be sure those observables inside the service will be unsubscribe in the end of the process and we will have happy users after all!

Thank you for reading,
Hope you enjoyed.

Discussion (0)