How to add Capacitor Storage value to Observable

Hi,
I have values stored with capacitor storage and retrieve them with the following code:

export async function getStorage(key: string): Promise<any> {
  const item = await Plugins.Storage.get({ key });
  return JSON.parse(item.value);
}

and then I have a method:

async getretrievedValue() {
    this.retrievedValue = await getStorage("retrievedValue");
    console.log(this.retrievedValue);
}

so this all works, but how do I set this as an Observable so that it will be available throughout the app and also automatically updates when the value changes?

Thank you for your help

There are a number of ways, but the single most important thing to remember is that there must always be a single source of truth.

In practice, this means the strategy I would recommend would be something like this:

interface Thingy {...}
class ThingyService {
  active$ = new BehaviorSubject<Thingy | undefined>(undefined);
  constructor(private storage: Storage) {
    storage.get("thingy").then(t => this.active.next(t));
  }
  watch(): Observable<Thingy | undefined> { return this.active$; }
  peek(): Thingy | undefined { return this.active$.value; }
  poke(t: Thingy | undefined): void { this.active$.next(t); this.storage.set("thingy", t); }
  clear(): void { this.poke(undefined); }
}

Important things to notice here:

  • nobody outside ThingyService should ever be interacting with underlying Storage when it comes to thingies
  • only read from Storage at well-defined times like app startup or resume after pause
  • optimistic writes to Storage are safe because of the previous rule
  • clients that can’t deal with undefined can use RxJS filters

Thank you very much @rapropos, this code will take me some time to try and understand - I am still struggeling to get my head around Observables, but I’m sure this will help me a lot!
Thank you.

You can wrap the promise in from. It’s in the rxjs lib. Turns promises into observables.

Thank you @bforsyth , would you perhaps be so kind as to give an example?

True, but that leads to a trap.

Now you are boxed in to having your single source of truth be device storage, which is slow, and must maintain strict discipline about waiting on writes lest you generate race conditions, which are hard to diagnose.

2 Likes

Ok thats true. I looked at your example and I think thats the better way of doing it. I usually dispatch an action with ngxs to update the value in the store.

@rapropos Does that change anything in your opinion? If I store the value in state management?

from(this.getStorage).subscribe(value => {
do something with value here. 
})

I frankly can’t say anything about ngxs in particular, because I’ve never used it. I looked at ngrx once, which appears to have a similar goal, but it reminded me too much of ORMs in terms of the bondage level and need for complete buy-in. There’s plenty of room for reasonable people to have different opinions about those sorts of tools, though, so I’m not intending to say I think they’re bad - just not my cup of tea.

Whatever you do, though, I think the rule of “only read from device storage at app start and resume time” has value.

1 Like

Ok that makes sense.