Storage set and get between tabs problem


#1

On tab 1, I’m using:

  ionViewDidEnter() {
    this.storage.get('genre').then((val) => {
      console.log(val.id);
    });

  }

On tab 2, I have a button that calls the following method on click:

  genreSelected(genre) {
    this.storage.set('genre', genre);
    this.tab.select(0);
  }

When a user clicks on the button in tab 2, it sets the storage variable and navigates to tab 1.

However, the result is the previously stored value and not the value that was just stored. I have to click back to tab 2, then click back to tab 1 and then it will show the updated value.

I can use nav.push instead of tab.select and it works, but if I click back to nav 2, it shows the nav 1 page, ugh.

Any ideas? I need the data on nav 1 to update immediately based on the user selection from tab 2.


#2

It looks like there might be issues with it not triggering Lifecycle events for tabs:

An alternative solution for you might be to create a provider that utilizes an observable.


#3

What’s strange is I just realized once I tested the app on my android device, it does actually work.

It doesn’t work in the browser lab though.


#4

I don’t think this will ever work consistently as written, leaving aside the tab lifecycle issue.

You don’t need (or really want) to use storage for things that are not intended to persist across app restarts. A shared service like @SigmundFroyd suggests is a better solution.

If you’re still reading, and you really do want genre to persist across app restarts, you must not ignore the return value of set. Until it resolves, you are not guaranteed that the write has completed, so any attempt to read is risking getting stale data.

this.storage.set('genre', genre).then(() => {
  // do navigation stuff in here
});
// don't do or call anything that 
// may attempt to read `genre` out here

#5

Thanks. In my case, I want the app to remember the user’s genre selection (it’s filtering a list of results based on genre upon app start). The only way to do this is by using storage, correct? Just want to make sure.

Thanks again.


#6

If you want to support this flow:

  • start app
  • select genre A
  • see only A things
  • quit app
  • restart app
  • see only A things without having to reselect genre

…then yes, storage is the right choice. Just make sure you hang any operations that may try to read off the then of the write as described above, and you should get consistent results. The tab lifecycle thing is still a concern, so maybe you should switch to a provider backed by storage:

class GenreService {
  genre = new ReplaySubject<string>(1);

  constructor(private _sink: Storage) {
    _sink.ready()
      .then(() => _sink.get('genre'))
      .then(stashed => this.genre.next(stashed));
  }

  update(g: string): void {
    this._sink.set('genre', g).then(() => this.genre.next(g));
  }
}

class PageA {
  genreSub: Subscription;
  genre: string;

  constructor(private _genres: GenreService) {}
  ionViewWillEnter(): void {
    this.genreSub = this._genres.genre.subscribe(g => this.genre = g);
  }
  ionViewWillLeave(): void {
    if (this.genreSub) {
      this.genreSub.unsubscribe();
      this.genreSub = undefined;
    }
  }
}

class PageB {
  constructor(private _genres: GenreService) {}
  genreSelected(genre: string) {
    this._genres.update(genre);
  }
}

#7

Really helpful, THANKS!