Sunday, February 2, 2014

MutationObserver as a Best (Dart) Practice for Watching Polymers


It's always something. At least that's how it feels sometime when coding Polymer.dart. Working with observable attributes does not always work with raw Dart. If you run the code through the Polymer asset transform for Dart Pub, then observables work fine in Dartium. But then, of course, things need to be compiled to JavaScript to work across the modern web (except for unstable Chrome). That usually works…

But it did not work for last night's code that tried to listen to the changes stream for a Polymer:
    // DOESN"T WORK IN IE!!!!!!!!!!!!!!!!!
    el.changes.listen((changes) {
      changes.forEach((change) {
        print(
          '[changes] '
          '${change.name} changed '
          'from: ${change.oldValue} '
          'to: ${change.newValue}.'
        );
      });
    });
Well, it works in Firefox, but when I try to load this in Internet Explorer, I get Object doesn't support property or method get$changes:



At this point, there is precious little that I can do about that specific error. Between the observable woes, the compile time, things not working in the dev channel version of Chrome, I feel as if I am working too much with the proverbial spit and duct tape already. So I abandon listening to the changes property, at least for the purposes of using it in Patterns in Polymer. Instead, I fallback to the JavaScript solution, which is to use mutation observers.

Mutation observers are a new browser standard that watch for changes (change watcher just doesn't sound as cool as mutation observer). Since they are new, they are not supported by Internet Explorer 10. But, unlike the changes property which does not seem to get translated by dart2js, mutation observers do compile—even down to Internet Explorer 10.

So the above changes based code becomes:
    var observer = new MutationObserver((mutations, _) {
      mutations.forEach((mutation) {
        print(
          '[mutation] ' +
          mutation.attributeName +
          ' is now: ' +
          mutation.target.attributes[mutation.attributeName]
        );
      });
    });
    observer.observe(el, attributes: true);
Just as I found with the JavaScript MutationObserver, the constructor for a Dart MutationObserver takes a callback function that will be invoked whenever observed changes are seen. For some reason the Dart callback requires two parameters, the second is the observer instance that was just created. Since I need that in scope for the call to observer.observe() anyway, I just stick with a placeholder variable for the second parameter.

With that, I have a Dart solution for observing Polymers that works. Even in IE:



Bother. I suppose I cannot complain too much. Living life on the bleeding edge for books like Patterns in Polymer fairly well invites struggles like this. Still, it forces me to keep a delicate balance between understanding what really works today and what is likely to work as readers are trying to use the book. In this case, I will likely stick with MutationObserver, if only because it fits the existing narrative a little better. Still, I would venture to guess that this will work in all supported IEs once IE 12 comes along and everyone can abandon IE 10. For me, that day can't come soon enough.

Day #1,015

No comments:

Post a Comment