TypeError: Cannot read property 'get' of undefined - STORAGE

#1
import { Injectable } from '@angular/core';
import { SessionProvider } from '../sessionprovider';
import { SqliteProvider } from '../sqlite/sqlite'
import {Storage} from '@ionic/storage'

/*
  Generated class for the ConnectioncheckproviderProvider provider.

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/
@Injectable()
export class ConnectioncheckproviderProvider {
  state:any;
  // static get parameters() {
  //   return [[HttpClient], [Storage]];
  // }
  
  constructor(private storage: Storage, public http: HttpClient,public session:SessionProvider,public sqlite:SqliteProvider) {
    window.addEventListener('online', this.changestate);
    window.addEventListener('offline', this.changestate);
      storage.get('age').then((val) => {
        console.log('from asyncTest --> Your age is', val);
      });

         setInterval(this.test,5000)

  }
  

  changestate(){
    this.storage.get('age').then((val) => {
      console.log('from asyncTest --> Your age is', val);
    });
    this.state=navigator.onLine ? 'online' : 'offline'
  }```

Please help: Why do I get undefined error - like in the title - when changestate is called, but in the constructor it works fine (get null for the value because there is nothing in storage)?
#2

Hi @DianLabuschagne,

You probably need to wait for the native plugin to be ready before you can use it in the constructor. You can simply wrap every this.storage call in the platform.ready() promise, so it doesn’t get called before the plugin has initialized (that’s why you get is undefined).

import { Injectable } from '@angular/core';
import { SessionProvider } from '../sessionprovider';
import { SqliteProvider } from '../sqlite/sqlite'
import {Storage} from '@ionic/storage'
import { Platform } from 'ionic-angular'; // Import Platform here

@Injectable()
export class ConnectioncheckproviderProvider {
  state:any;
  // static get parameters() {
  //   return [[HttpClient], [Storage]];
  // }
  
  // Inject Platform in the constructor
  constructor(private storage: Storage, public http: HttpClient,public session:SessionProvider,public sqlite:SqliteProvider, private platform: Platform) {
    window.addEventListener('online', this.changestate);
    window.addEventListener('offline', this.changestate);
    // Wait for platform.ready()
      platform.ready().then(() => storage.get('age')).then((val) => {
        console.log('from asyncTest --> Your age is', val);
      });

         setInterval(this.test,5000)

  }
  

  changestate(){
    // Wait for platform.ready()
    this.platform.ready().then(() => this.storage.get('age')).then((val) => {
      console.log('from asyncTest --> Your age is', val);
    });
    this.state=navigator.onLine ? 'online' : 'offline'
  }
}

Best,
Rodrigo

#3

Hi Rodrigo

Thank you! but I the weird thing is that it works when called in the constructor, nut not from the changestate() function :confused:. But I tried what you suggested this time it is not recognising the platform in the change state function:

error I get:
TypeError: Cannot read property 'ready' of undefined

import { Injectable } from '@angular/core';
import { SessionProvider } from '../sessionprovider';
import { SqliteProvider } from '../sqlite/sqlite'
import {Storage} from '@ionic/storage'
import { Platform } from 'ionic-angular'; // Import Platform here
/*
  Generated class for the ConnectioncheckproviderProvider provider.

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/
@Injectable()
export class ConnectioncheckproviderProvider {
  state:any;

  
  constructor(private platform:Platform,private storage: Storage, public http: HttpClient,public session:SessionProvider,public sqlite:SqliteProvider) {
    window.addEventListener('online', this.changestate);
    window.addEventListener('offline', this.changestate);
    // this.handleStateChange().then(()=>{
      this.platform.ready().then(() => this.storage.get('age')).then((val) => {
        console.log('from asyncTest --> Your age is', val); // this succeeds 
      });
         setInterval(this.test,5000)
  
  }
  

  changestate(){
    this.platform.ready().then(() => this.storage.get('age')).then((val) => {
      console.log('from changestate --> Your age is', val);   //This fails when I make the online/offline event trigger
    });
    this.state=navigator.onLine ? 'online' : 'offline'
  }```
#4

FOUND THE ANSWER I WAS LOOKING FOR HERE:

it was a scope issue. I did the following:
added .bind(this) to the event listeners in the constructor ->

window.addEventListener(‘online’, this.changestate.bind(this));
window.addEventListener(‘offline’, this.changestate.bind(this));

1 Like
#5

Yes, I was actually writing the same thing, I’m glad you found the problem. You can also do:

window.addEventListener('online', () => this.changestate());

As arrow functions also share the this context with the inner function.