Thursday, December 5, 2013

Canceling Polymer Ajax Listeners (Dart)


Up today, a bit of cleanup on the <polymer-ajax> work from yesterday. My pull request was merged into the Dart version of the Polymer Elements project, so I can switch back to the real thing instead of my fork. I would also like to double check that I am using <polymer-ajax> effectively.

Switching back to the real project is easy. This is Dart, after all. I swap the path dependency that had pointed to my fork, replacing it with the GitHub repository of the real thing (the most recently published version does not work with Dart 1.0 yet, so I use the GitHub repo):
name: change_history
dependencies:
  polymer: any
  polymer_elements:
    git: https://github.com/ErikGrimes/polymer_elements
    # path: /home/chris/repos/polymer_elements
After a quick pub upgrade, I am ready to go, using the the most recent version of polymer_elements including my pull request. Yay Dart!

Next up, I sort through the code in an effort to identify some niceties of <polymer-ajax> that I might not be using effectively. In the web page itself, I am wrapping my <polymer-ajax> element as:
    <store-changes>
      <!-- <polymer-localstorage name="store-changes" value="{{value}}"></polymer-localstorage> -->
      <polymer-ajax url="http://localhost:31337/widgets/change-history"
                    handleAs="json">
      </polymer-ajax>
      <!-- changes will originate from elements here ... -->
    </store-changes>
The handleAs JSON means that I do not need to manually decode JSON responses back from <polymer-ajax>. Unfortunately, I still have to manually encode the JSON when storing change history:
@CustomTag('store-changes')
class StoreChangesElement extends PolymerElement {
  StoreChangesElement.created(): super.created();
  // ...
  get store => children.
    firstWhere((el) => el.localName == 'polymer-ajax');
  // ...  
  storeChange(e) {
    // ...
    store
      ..method = 'POST'
      ..xhrArgs = {'body': JSON.encode(record)}
      ..go();
  }
}
I am not too fussed by this. Before yesterday, I did not even think it was going to be possible to do encode the body of the Ajax request in JSON. I am a bit off the happy path here, so I am happy to do a little extra work.

That said, I can make use of the handleAs JSON when retrieving the records:
@CustomTag('store-changes')
class StoreChangesElement extends PolymerElement {
  Map record = {'history': []};

  StoreChangesElement.created(): super.created();

  enteredView() {
    super.enteredView();
    _fetchCurrent();
    addEventListener('change', storeChange);
  }
  void _fetchCurrent() {
    var subscription;

    subscription = on['polymerresponse'].listen((e){
      print(e.detail['response']);
      record = e.detail['response'];
      subscription.cancel();
    });
  }
The record needs to be a Map object. Without <polymer-ajax> decoding the response for me, I would have to manually convert that response each time. It might not seem like a huge win, but it is really is the little niceties in a project that make it a pleasure.

Of note in _fetchCurrent() is how I have to subscribe and cancel the listener. I cannot declare and assign subscription in the same statement because it will lead to errors like:
Internal error: 'http://localhost:8080/packages/change_history/store_changes.dart': Error: line 11 pos 9: initializer of 'subscription' may not refer to itself
    var subscription = on['polymerresponse'].listen((e){
        ^ 
I have no luck getting removeEventListener() to remove listeners when used in conjunction with addEventListener(), which is why I wind up using the on['polymerresponse'] stream instead. Happily, it works just fine. I am able to get the initial load and then cancel the subscription so that subsequent GET requests might be handled elsewhere.

That should do it for <polymer-ajax>. Tomorrow, I will explore strategies for swapping it and <polymer-localstorage>.


Day #956

No comments:

Post a Comment