Ionic Storage as promise with providing initial data

Hello,

so I would like to achieve the following within my Ionic Storage provider (Ionic v. 3):

  • on app open, check if storage is available
  • if it is not available, create storage with http request, if http request not possible (return null), then populate with new data on the fly
  • if available, simply use existing one.

This is my solution (provider):

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage';

@Injectable()
export class MovieProvider {

  movieCollection: any;
  
  private initData() {
    this.buildMovieItemsViaHttp().then(data => this.movieCollection = data);
    if (this.movieCollection != null)
    {
      this.storage.set('storageMovieCollection', this.movieCollection);
    } else {
      //this.storage.set('storageMovieCollection', bla...load some generated data on the fly);
    }
  }

  private buildMovieItemsViaHttp(){
    return new Promise(resolve => {
        this.http.get('assets/data/movieCollection.json') //will be replaced with actual server data
          .subscribe(res => {
            resolve(res);
            console.log(res)
          });
    });
  }

  getMovieItems() {
    this.storage.get('storageMovieCollection').then((data) => {
      return data;
    });
  }

  constructor(private http: HttpClient, private storage: Storage) {
    this.storage.get('storageMovieCollection').then((data) => {
      if(data != null)
      {
        this.initData();
      }
      else
      {
        //just use existing one...
      }
    });
  }

The console.log will return all the items. So this is working.

However, doing the following inside my init will always return undefined:
this.buildMovieItemsViaHttp().then(data => this.movieCollection = data);

Apparently it is not able to fetch the data from the promise. I fear I am using this wrong.

Thanks in advance for your ideas and suggestions!

private async initData() {
   this.movieCollection = await this.buildMovieItemsViaHttp();
    if (this.movieCollection != null)
    {
      this.storage.set('storageMovieCollection', this.movieCollection);
    } else {
      //this.storage.set('storageMovieCollection', bla...load some generated data on the fly);
    }
  }
3 Likes

Also do yourself a favour… don’t cast the type to any. Cast to an interface that represents the shape of the data.

1 Like

thanks ALOT for that, really I have been sitting for hours by now and rewrote everything couple of times without finding a solution :smiley:

I have one more issue:

My mainpage would load all the items from the provider storage on startup, like this:

  constructor(private navCtrl: NavController,
              private navParams: NavParams,
              private movieItemProv: MovieNewsProvider) {
  }

  ionViewWillEnter() {
    this.movieItemProv.getMovieItems().then(data => this.movie = data);
  }
  
  ionViewDidLoad() {
    this.movieItemProv.getMovieItems().then(data => this.movie = data);
  }

and this is my getMovieItems provider function to return the storage items:

  getMovieItems() {
    return new Promise(resolve => {
      this.storage.get('storageMovieCollection').then((data) => {
        resolve(data);
      });
    })
  }

the mainpage would only populate however if I switch the tabs, apparently because the storage is not yet finished with populating the data. However, I thought the promise would actually fix that.

So my question is: how can I ensure that my provider would finish all the data preperation/loading before the actual app starts? Should I put the data loading logic inside the app.components.ts to have the data loaded on app start?

Thanks in advance!

Probably not a bad idea.
Just as long as that process doesn’t take too long.

1 Like

You probably don’t want to lock yourself into this. User A has a great experience, while User B has a terrible experience, based on how fast their phone handles the loading. Instead, you can start the process of loading data in app.component.ts, but build your homepage so it is ready to display something cool even if not everything is loaded yet, and then displays the rest of the content over time. You could use the async pipe for this.

I would plan to load something small immediately, and, once that’s done, to load everything else.

2 Likes