Sunday, December 1, 2013

Polymer Code Cleanup with Polymer-Elements


Having slept on it, the idea of establishing pub-sub chains of Polymer elements has, if anything, grown on me. I originally intended to investigate inheritance and Polymer's extends option tonight, but… inheritance. Instead, I continue to poke at interaction between Polymer elements by taking a look at the Polymer project's own elements.

I finished last night with a Polymer that listened for events from another Polymer:
    <store-changes><!-- Polymer to store change events in localStorage -->
      <change-sink><!-- Polymer to normalize change events -->
        <div contenteditable><!-- plain old editable div -->
          <!-- ... -->
        </div>
      </change-sink>
    </store-changes>
I wound up putting a lot of localStorage code into <store-changes>. It would be nice to separate out a little of that localStorage logic so that <store-changes> can worry only about what to store.

Well, it so happens that the Polymer project has a <polymer-localstorage> element. To use that, I need to install polymer-elements with Bower. Bower is yet another package manager for JavaScript-land, which, interestingly enough, is installed with another JavaScript package manager, npm:
$ npm install -g bower
After dealing with npm nonsense (does that ever work right the first time?), I am ready to bower install polymer-elements:
$ bower install polymer-elements
Next, I import the element into my web page:
    <!-- 1. Load Polymer before any code that touches the DOM. -->
    <script src="scripts/polymer.min.js"></script>
    <!-- 2. Load component(s) -->
    <link rel="import" href="scripts/change-sink.html">
    <link rel="import" href="scripts/store-changes.html">
    <link rel="import" href="bower_components/polymer-elements/polymer-localstorage/polymer-localstorage.html">
And place it inside my custom <store-changes> element:
    <store-changes>
      <polymer-localstorage name="store-changes" value="{{value}}"></polymer-localstorage>    
      <change-sink>
        <!-- ... -->
      </change-sink>
    </store-changes>
That will create a localStorage entry at "store-changes". Better yet, it will take care of marshalling the data as JSON for me. This should cut down significantly on the work that I need to do. To use this in <store-changes>, I grab a reference to <polymer-localstorage> in the ready() callback:
<polymer-element name="store-changes">
  <script>
    Polymer('store-changes', {
      ready: function() {
        this.store = this.querySelector('polymer-localstorage');
        this.addEventListener('change', this.storeChange);
      },
      // ...
    });
  </script>
</polymer-element>
Then, when those changes are detected, I store them using this.store:
    Polymer('store-changes', {
      ready: function() {
        this.store = this.querySelector('polymer-localstorage');
        this.addEventListener('change', this.storeChange);
      },
      storeChange: function(e) {
        var change = e.detail,
            store = this.store.value || {};

        var update = {
          current: change.is,
          previous: store.previous || []
        };
        update.previous.unshift(change.is);
        update.previous.splice(10);

        this.store.value = update;
      }
    });
There is still a fair bit of code in there, but now it all deals with initial values and managing the history (which only contains the 10 most recent changes). There is nothing in there about JSON nor is there any overhead associated with creating the default JSON record. This new <polymer-localstorage> element does it all for me.

If I redefine yesterday's get() in terms of <polymer-localstorage>:
      get: function(i) {
        return this.store.value.previous[i];
      },
Then I am again able to retrieve the list of changes—even after a page reload:
el = document.querySelector('store-changes')
el.get(3)
"<h1>Change #4</h1>"
el.get(2)
"<h1>Change #3</h1>"
el.get(1)
"<h1>Change #2</h1>"
el.get(0)
"<h1>Change #1</h1>"
Nice!

Actually, it is not all bad with respect to inheritance in Polymer—some of the examples look more like implementation than inheritance. That is especially interesting using a UI-less base for a UI implementation. I will probably take a look at that tomorrow.


Day #952

No comments:

Post a Comment