0

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 ?

PierBJX
  • 2,093
  • 5
  • 19
  • 50
  • You provide your service in "root", making it a singleton. Meaning, you will have shared state throughout the app. As for the extra GET request from destroyed component, you need to pipe in a `takeUntil(this.destroyed)` operator before subscribing to the stream. – John Doe Aug 16 '18 at 18:45
  • If I add the takeUntil(this.destroyed), do I have to change the root to singleton? takeUntil is a npm module ? (this one: https://github.com/NetanelBasal/angular2-take-until-destroy) @JohnDoe – PierBJX Aug 16 '18 at 18:48
  • takeUntil is an RxJS pipeable operator. Check this out https://www.learnrxjs.io/operators/filtering/takeuntil.html – John Doe Aug 16 '18 at 19:03

1 Answers1

0

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.
    
John Doe
  • 4,574
  • 2
  • 26
  • 30
  • 1
    I asked about this [here](https://stackoverflow.com/questions/49801713/angular-proper-time-to-unsubscribe) and if it is a single implementation, an unsubscribe is overkill. – rhavelka Aug 16 '18 at 20:58
  • @rhavelka in the OP's case, there is a source stream emitting events that are most likely `switchMap`'ped to an http request stream, meaning it will be called each time. Being mindful about your unsubscribes is not an overkill, but a sign of conscious engineer. – John Doe Aug 17 '18 at 19:35