Storage: get function returns object but object-method cannot be called

Hi,
I have a storage set up

import { Storage } from '@ionic/storage';
export class HomePage {
...
constructor(private storage: Storage, ...){...}
  set_fun(foo){
      this.storage.set("test", foo);
  }
}

The foo object, which has a method “get_name()” is stored, but when I try in another page to call

this.storage.get('test').then((val) => {
        this.testvar = val.get_name();
    });

I get the error:
Uncaught (in promise). Type Error. val.get_name() is not a function

Obviously the get function does not know that val is a foo-type object. How do I deal with that?

(Using ionic 3)

Do you really have backquotes and not single quotes around test?

Yes ups. I changed it - but this did not cause the issue…

I haven’t tried but, but are you sure that you can store functions in ionic storage? It says: Storage is an easy way to store key/value pairs and JSON objects. JSON Objects have no functions.

You could implement a class with a toJSON method to extract the state from the object for storing and also implement a fromJSON static method for that class, that restores that object.

Oh yeah I just realize that you are probably right! Is there no way to store class-objects in Ionic? This would make things a lot easier. I find it - compared to other programming languages - also quite complicated to share data and methods between pages, which would allow to store i.e. simply an index and recover from any page an object from an array by using this global index. But to share that array and the corresponding method is… puh.

Or is there a simpler and more intelligent way to handle data (objects) that must be stored and be available over multiple pages?

Just put it in a provider.

You could write a serializable interface and let your classes implement it.
I am using a pattern like this:

interface Serializable<T, U> {
  toJSON(): U;
  fromJSON(data: U): T;
}

interface MainData {
  propA: string;
  propB: NestedData;
  propC: Array<NestedData>;
}

interface NestedData {
  propD: string;
}

class Main implements Serializable<Main, MainData> {
  propA: string;
  propB: Nested;
  propC: Array<Nested>;
  toJSON(): MainData {
    return {
      propA: this.propA,
      propB: this.propB.toJSON(),
      propC: this.propC.map(n => n.toJSON())
    };
  }
  fromJSON(data: MainData): Main {
    this.propA = data.propA;
    this.propB = new Nested().fromJSON(data.propB);
    this.propC = data.propC.map(n => new Nested().fromJSON(n));
    return this;
  }
}

class Nested implements Serializable<Nested, NestedData> {
  propD: string;
  toJSON(): NestedData {
    return {
      propD: this.propD
    };
  }
  fromJSON(data: NestedData): Nested {
    this.propD = data.propD;
    return this;
  }
}

// Build objects
const main = new Main();
main.propA = 'Hello';
main.propB = new Nested();
main.propB.propD = 'World';
const array = [new Nested(), new Nested()];
array[0].propD = 'One';
array[1].propD = 'Two';
main.propC = array;

// For storing all objects
const completeDataToStore = main.toJSON();

// Restoring all class objects
const restoredClassObjects = new Main().fromJSON(completeDataToStore);

Would be nice to see some other patterns :star_struck:

Thank you for that comment! This was what I was looking for!

Interesting. But quite complicated. Is it common practice in IONIC to use JSON objects for storage only?

Marshaling to and from JSON is expensive. For performance, it’s better not to use JSON at all.

Maybe my naming was bad. I only map the class objects to simple data structures, that are json valid to transfer them for example with a rest api. I do not use JSON.parse and JSON.stringify. I don’t know if ionic storage uses it internally, but I would assume it. I don’t know a way of storing js objects without converting them to json or string.

@AaronSterling what would you recommend?

Well you don’t need to do either one, with the Firestore database being the example that’s maybe most interesting to Ionic programming. (Though maybe Firestore stringifies under the hood? I’m not sure…) But I really like the code you’ve posted, so I wasn’t talking about any approach you’ve been taking.

But let’s suppose that for whatever reason you need to parse to JSON before doing operation X. If you have to do it anyway, I’d suggest you look at offloading Operation X to a web worker.

Thanks, I like the idea of using web workers for that.