Sunday, April 20, 2014

Watching Polymer Attributes Is Now a Whole Lot Easier

With the 1.1 edition of Patterns in Polymer due in but a few hours, I do not have much time for blog posts, but the gods of my chain must have their daily sacrifice.

So I try out my AngularJS application that uses Polymer web components. I would like to see if, as I found last night, some of the infrastructure that I have created around it is really still necessary.

Of course the application has to still work for that investigation. Naturally, it does not. After upgrading to the latest Polymer and AngularJS versions (0.2.2 and 1.2.16, respectively, at the time of this writing), I get a big ol' injector error:
Error {stack: "Error: [$injector:modulerr] Failed to instantiate …:8000/bower_components/angular/angular.js:21459:5", message: "[$injector:modulerr] Failed to instantiate module …er_components%2Fangular%2Fangular.js%3A1379%3A20)"}
 "Error: [$injector:modulerr] Failed to instantiate module pizzaStoreApp due to:
Error: [$injector:nomod] Module 'pizzaStoreApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.$injector/nomod?p0=pizzaStoreApp
    at http://localhost:8000/bower_components/angular/angular.js:78:12
    at http://localhost:8000/bower_components/angular/angular.js:1611:17
Almost lost in there is the root cause, which is that the pizzaStoreApp module is not available for injection. It is required by the root element of my single page application's HTML:
<!doctype html>
<html ng-app="pizzaStoreApp">
  <!- ... -->
This is one of those things where I have to wonder how it ever worked. My module is, in fact, named PizzaStoreApp, not pizzaStoreApp:
var PizzaStoreApp = angular.module('PizzaStoreApp', [
Mercifully, that is an easy enough fix. After making the first letter in the module's name lowercase, everything is working fine. Everything including my angular-bind-polymer directive, which still ensures two-way binding of Angular and Polymer attributes so that Angular can see the current value of the <x-pizza>'s internal pizza state:

That is pretty nice to see. But what about all of the ceremony through which I went to ensure that Polymer was loaded and applied before processing my Angular directive?

Well, it seems that it is no longer necessary. I comment out my onPolymerReady() function whose returned promise completes when the observe property is seen:
      // When Polymer is ready, establish the bound variable watch
      // onPolymerReady().
      //   then(function(){
          // When Polymer sees a change to the bound variable,
          // $apply / $digest the changes here in Angular
          var observer = new MutationObserver(function() {
          observer.observe(polymer(), {attributes: true});

          for (var _attr in attrMap) {
              function() {return element.attr(_attr);},
              function(value) {
                scope[attrMap[_attr]] = value;
        // });
I am not even listening for a polymer-ready event here, but running the mutation observer code immediately upon evaluating the directive. And it works just fine. Angular-bind-polymer is still able to see the Polymer change and set the corresponding property in Angular.

That is very exciting.

I am a little skeptical that it works, but I try moving the various angular and polymer script/template load order around in the containing document—and the bound variables continue to update. I even try this in Firefox and Internet Explorer—and it still works.

I am unsure when this got fixed—or even if the fix was in Polymer or Angular. It matters only if there is a chance that the condition might return, but that is what tests are for—and it is easier to test that something continues to work than for a broken thing to start working. So yay!

Now back to editing...

Day #40

No comments:

Post a Comment