Search code examples
htmldartdart-polymer

How to monitor indexdb stores for content changes?


I currently have a PolymerElement which is binding to a observable list, and using

<template repeat="{{cardnames}}">
    <div>{{ }}</div>
</template>

So far, so good. The cardnames is populated from a IndexDB store, I'm using lawndart for this. It works for getting all the items at startup, but when I add a item to the database, from a separate PolymerElement, there is no way to update the cardnames list from this other PolymerElement. So one of the ideas I have come up with, without putting all this logic into the same PolymerElement, of having the one with the cardnames in it monitor the Database for changes, and update the list from there, when a change happens. My problem is I don't know if the is already a change event that can be listened to, and I was hoping someone could enlighten me of if there is, and where to find it or show me how to do it.

Of coarse I could run a background Isolate process to check for changes, or a timer of some sort, but that seems clumsy, costly and an increase in complexity I could do without.

Thanks


Solution

  • OK I'm going to answer my own question.

    I think the answer to if there is a IndexedDB event that is triggered when an item is added, is no. I'd like to be proven wrong, but the only update event I've seen is for version updates, not added content updates. I shouldn't be surprised by this.

    Anyway, I found that using the code below, unsurprisingly, works, though I'd have preferred to use an event generated by IndexedDB or something, but you don't always get what you want. This is done using Lawndart, which effectively uses IndexedDb in most modern browsers.

    ...
    //define an observable to hold the list
    @observable List<String> cardnames;
    
    static const INTERVAL = const Duration(seconds: 1);
    Timer poller;
    ...
      poller = new Timer.periodic(INTERVAL, pollDB);
    ...
    void pollDB(Timer timer) {
      Store db = new Store("magic-card-collection", "magic-card");
      db.open().then((_) {
        db.keys().forEach((item) {
          if(!cardnames.contains(item)) {
            cardnames.add(item);
            print("added " + item);
          }
        });
      });
    }
    

    Now every time a item is added to cardnames, the view gets updated, dynamically as more are added to the DB. So I can now add cards from any outside source, and the view will be updated within seconds.

    UPDATE:

    With some help from both Seth Ladd and the Polymer documentation, I figured out the best way is not to poll the db, but to have one central DB store contained in one element, have the other elements fire custom events when they do something, passing the info as part of the fired event, and having the controller element listen for those events and both add to the store plus update the UI. For example create an element that collects data to put in the db, and have it fire an event when finished collecting that info.

    <polymer-element name="collect-data">
     <template>
      <div>
        <button on-click="{{save}}">Ok</button>
      </div>
    
     </template>
     <script type="application/dart" src="collectdata.dart"></script>
    </polymer-element>
    

    The collectors dart file

    @CustomTag('collect-data')
    class CollectData extends PolymerElement {
    
      CollectData.created() : super.created();
    
      void save(Event e, var detail, var target) {
        fire("update", detail: "hello");
      }
    }
    

    The controller

    <polymer-element name="app-controller">
     <link rel="import" href="collectdata.html">
     <template>
      <div>
        <collect-data on-update="{{save}}"></collect-data>
      </div>
    
     </template>
     <script type="application/dart" src="appcontroller.dart"></script>
    </polymer-element>
    

    The app controller dart file

    @CustomTag('app-controller')
    class AppController extends PolymerElement {
    
      AppController.created() : super.created();
    
    
      void save(Event e) {
        var data = e.detail;
        //update your db here, which would, if you had one, include updating an observable list
        ...
      }
    }
    

    The important things to note are the method

    fire('update', detail: ...);
    

    The detail can be any valid object, I think. I know you can pass a string or a dict to it. The other part is

    <collect-data on-update="{{save}}"></collect-data>
    

    The thing that fires the event calls it update, the listener listens to on-update. I'll leave it to you to figure out the pattern requirement here.

    However the DB still doesn't emit a changed event that I know of at the moment.