Angular – Behavior of shared service subscribe

Issue

Using Angular I have a service to share some variable from different components.
Like this:

import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
@Injectable()
@Injectable({
  providedIn: "root"
})

/**
 * Service to manage all the global variables in order to use it in different components
 */
export class SharedService {

  // Global variable of the path 
  private rPathSource = new BehaviorSubject(""); // Set up the source
  currentRPath = this.rPathSource.asObservable(); // Make it Observable

 constructor() {}

  /**
   * Function to change the global path from a component
   * @param path string of the path of the R Folder for the result of the ML
   */
  changeRPath(path: any) {
    this.rPathSource.next(path);
  }
}

Then from a component I subscribe to it. Like this:
Component 1

constructor(private shared: SharedService) {}

ngOnInit() {
    this.shared.currentRPath.subscribe(RPath => {
      this.currentRPath = RPath;
      // HERE I DO A GET REQUEST
    });
  }

And from another component I change the variable like this:
Component 2

this.shared.changeRPath("");

I have a sidenav bar with some buttons and each button change the url and the component loaded with ng content.

<ng-content></ng-content>

When I press the button to redirect on the component 1 I susbcribe to the variable and the get request is done. Everything is fine.

The problem is when I press the button to redirect on the component 2 the shared variable changes and because I susbcribe on the component 1 it does the get request again. Indeed, the get request is in the callback of the subscribe.

But what is weird is that the component 1 is not load anymore because it is the component 2. It is not supposed to be destroyed when the component changes ?

Solution

You must not forget to unsubscribe to avoid memory leaks in these dangling subscriptions.

Here are 2 ways to do that:

  1. Use takeUntil:

    export class MyComponent implements OnDestroy, OnInit {
      private readonly destroyed = new Subject<void>();
    
      constructor(private readonly shared: SharedService) {}
    
      ngOnInit() {
        this.shared.currentRPath.pipe(takeUntil(this.destroyed)).subscribe(/*...*/);
      }
    
      ngOnDestroy() {
        this.destroyed.next(undefined);
        this.destroyed.complete();
      }
    }
    
  2. Unsubscribe (useful when you have a single subscription):

    const mySubscription = this.shared.currentRPath.subscribe(/*...*/);
    mySubscription.unsubscribe(); // when done.
    

Answered By – John Doe

Answer Checked By – Mildred Charles (AngularFixing Admin)

Leave a Reply

Your email address will not be published.