Search code examples
angulartypescriptglobalbehaviorsubject

How to use Subjects to share global data in angular 6


I have been trying to find the best solution to share some data beetween two componentes that share the same parent.

I am using an angular-material stepper. Step 1 has one component and step 2 has another one. What i am trying to do is to "click" 1 button in the component from the step 1 and refresh an array of data that affects component in step 2.

This is my code:

Global service:

  export class GlobalDataService {
  private reserveSource = new BehaviorSubject<any[]>([]);

  currentReserve = this.reserveSource.asObservable();

  constructor() { }

  changeReserve(reserve: any[]) {
    this.reserveSource.next(reserve)

  }
}

Component 1 that tries to update:

setSpace(id) {
this.apiObservableService
  .getService('http://localhost:8080/Spaces/' + id)
  .subscribe(
    result => {
      this.space = result;
      this.globaldataservice.changeReserve(result.reserves);
      sessionStorage.setItem('currentSpace', JSON.stringify(result));
    },
    error => console.log(error)
  );

}

Component 2 that tries to read and refresh:

ngOnInit(): void {

    this.currentUser = JSON.parse(sessionStorage.getItem('currentUser'));
    this.currentSpace = JSON.parse(sessionStorage.getItem('currentSpace'));

    this.globaldataservice.currentReserve.subscribe(message => this.reserves = message)
    console.log(this.reserves);
  }

Solution

  • Quite frankly, your code should work fine, but here is how I deal with it, in case I missed something in your code.

    GlobalDataStore should also give out the BehaviourSubject as Observable, so you can subscribe to it.

    Also make behavioursubject private.

    export class GlobalDataService {
      private reserveSource = new BehaviorSubject<any[]>([]);
    
      get reserveSource() {
           return this.reserveSource.asObservable();
      }
    }
    

    Then just subscribe to it in the component.

    As a bonus, I also implement these functions in my stores (since I am also using BehaviourSubject)

    //Gets the last value, that was pushed to the BehaviourSubject
    get reserveSourceLastValue() {
       return this.reserveSource.getValue();
    }
    
    //Deep clones the last value, if I want a precise copy for form editing buffer
    get reserveSourceForEdit() {
        return __lodash.cloneDeep( this.reserveSource.getValue() );
    }
    

    PRO PERFORMANCE TIP!

    As a last note, if you do not unsubscribe from observables, then they are left open forever, even after the component itself is destroyed. To make matters worse, since you have the observable initialized in ngOnInit, then every time you route to and from this component, a new subscription is created.

    Please read this article on how to gracefully unsubscribe from subscriptions in components.

    Angular/RxJs When should I unsubscribe from `Subscription`