2

I have a shared service as follows:

data = new BehaviorSubject<any[]>([]);
constructor(userService: UserService){
  if (localStorage.getItem('data') === null) {
    userService.getAllData().subscribe(results =>

      this.data.next(results)
 }
  else {
    this.loadData()
  }
}

loadData() {
  let data = JSON.parse(localStorage.getItem('data');
  this.data.next(data);
}

setData(data) {
  localStorage.setItem('data', JSON.stringify(data))
  this.data.next(data)
}

And then on my component on ngOnInit() I have :

ngOnInit() {
  this.sharedService.data.subscribe(results =>
    this.allData = results;
  )
}

itemChange() {
  this.allData.slice(index, 5);
  this.sharedService.data.next(this.allData)
}

and OnLogout I have :

   localStorage.removeItem('data')

The issue is that on first page reload, the service gets called and I have the data as expected, I make changes and then after I logout, and log back in, on the storage I don't have the data key anymore, but yet the sharedService doesn't get called again, instead on the components onInit the this.sharedService.data is already populated from the last time.

How do I make it call the sharedService everytime so that it checks whether the item('data') is there or not, as it is on the service constructor ?

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
JennyJ
  • 53
  • 1
  • 8
  • CHeck out :https://stackoverflow.com/questions/43348463/what-is-the-difference-between-subject-and-behaviorsubject – Shashank Vivek Apr 04 '18 at 19:03
  • @ShashankVivek If I use Subject, I won't be able to subscribe on the component ? How do I do it then? Because as it is, it works but when I logout and log back in, onngOnInit the data from the shared service is already populated. I need to refresh the page, so that It calls the service again and then it sees and checks the condition it has on the constructor. – JennyJ Apr 04 '18 at 19:28

3 Answers3

5

I'd suggest you restructure your service then. Do it in this way.

You do not let Subscribers subscribe to the data-BehaviorSubject itself but to a getter-method instead that returns your object as an Observable. Same effect but you now have the possibility to call other private methods in addition whenever a subscription occurs.

import { Observable } from 'rxjs/Observable';

private data = new BehaviorSubject<any[]>([]);

constructor(private userService: UserService){}

getData(): Observable<Array<any>> {

    // called once with/by each subscription    
    this.updateData();

    return this.data.asObservable();
}

And you now call, with each new subscription, the private method updateData(). This method will do the check you currently do in your constructor. But this check will happen now not only once when the service gets instantiated but with each new run of your app whether you shut down the browser or simply log out.

getDataValue(): Array<any> {
    return this.data.getValue();
}

setData(val: Array<any>) {
    localStorage.setItem('data', JSON.stringify(val));
    this.data.next(val);
}


private updateData(): void {
       const storage = localStorage.getItem('data');

       if (storage === null) {

          this.userService.getAllData().subscribe(results => {
             this.data.next(results);
          }

      } else {
          this.data.next(JSON.parse(storage));
      }
}

And in your component:

import { Subscription } from 'rxjs/Rx';

private subscription: Subscription;

ngOnInit() {
   this. subscription = this.sharedService.getData().subscribe(results =>
      this.allData = results;
   )
}

ngOnDestroy() {
    if (this.subscription) {
        this.subscription.unsubscribe();
    }
}

This should do.

  • @JennyJ: I hope this now approach helps. If so, I'd really appreciate if you would mark this answer as solution an give it an upvote. –  Apr 04 '18 at 20:41
  • Absolutely! Though for some reason on loggin back in it takes a second to display the correct data and reload. this definitely helped! Will mark it as correct :) Thanks a lot! – JennyJ Apr 04 '18 at 20:54
  • Don't mention it. :) –  Apr 04 '18 at 20:57
  • Quick question, could it be that it's subscribing twice or something ? Because allData that I display, gets refreshed TWICE whenever I navigate away and back. – JennyJ Apr 04 '18 at 22:01
3

I guess you have to reset the value what you are emitting through behaviourSubject by emitting initial value. May be not the perfect answer but I believe it will work.

The reason behind this is custom observable will not complete itself, you need to do that manually.

1

Extend your code in your component. Implement a Subscription so you can then unsubscribe from the service if you leave/close the component:

import { Subscription } from 'rxjs/Rx';

private subscription: Subscription;

ngOnInit() {
   this. subscription = this.sharedService.data.subscribe(results =>
      this.allData = results;
   )
}

ngOnDestroy() {
    if (this.subscription) {
        this.subscription.unsubscribe();
    }
}

PS: if you don't want to care for the deletion of your objects in the browser's storage use sessionStorage instead of localStorage. All content inside sessionStorage is deleted as soon as you close the current tab or the whole browser.

  • Same issue again. Even with this, when I logout and log back in, the old data is still showing, until I refresh :| – JennyJ Apr 04 '18 at 19:59