Friday, January 31, 2014

Publishing to Bower: a Workflow for an AngularJS Directive


The question for today is, how do you extract a working Angular directive into a published Bower package?

From last night, I have my generalized solution for double binding Polymer variables in AngularJS (pushing changes into Polymer works fine, but seeing changes from Polymer in Angular needs a little help). I can change attributes and variable names in Angular templates:
<pre ng-bind="asdf"></pre>
<p>
  <x-pizza bind-polymer state="{{asdf}}"></x-pizza>
</p>
And, thanks to last night's generalized bind-polymer directive, it just works™:



I can add stuff to my <x-pizza> Polymer and Angular sees the change—even with whatever ridiculous variable name I might put in there. So I am good to go with this approach, except…

It likely will not fit a nice narrative in Patterns in Polymer—at least not a consistent narrative between the Dart and JavaScript versions of Polymer. The problem is that the Dart and JavaScript solutions are at completely different abstraction levels currently. Dart has a package that does this (angular_node_bind) and my JavaScript solution requires the reader to write their own Angular directive. Which means… I have a darn good excuse to publish my first Bower package!

I start with a new, local Git repository. Before publishing this to Bower, I ought to make sure that it works. It seems like Bower will only work with local Git repositories (not directories), I start angular-bind-polymer:
➜  repos  mkdir angular-bind-polymer
➜  repos  cd !$
➜  angular-bind-polymer  git init .
Initialized empty Git repository in /home/chris/repos/angular-bind-polymer/.git/
Next, I initialize this as a Bower project with bower init:
➜  angular-bind-polymer git:(master) bower init
I mostly accept the defaults from the very nice initialization script. The customizations are specific to this being an Angular module (it will depend on AngularJS) and how I organize the package (I will create the code directly in the top-level of the repository). The differences from the defaults in the resulting bower.json are then:
{
  "name": "angular-bind-polymer",
  // ...
  "description": "Angular directive for *double* variable binding of Polymer attributes.",
  "main": "angular_bind_polymer.js",
  // ...
  "dependencies": {
    "angular": "~1.2.9"
  }
}
Now for the main file, angular_bind_polymer.js. I have the Angular directive ready to go, I only need place it in the main file properly. For that, I assume that Angular will already be loaded, which will make the angular global variable available. I need to declare this as a module and the unofficial convention for these things seems to be prefixing the module name with a GitHub ID (eee-c in my case). So angular_bind_polymer.js becomes:
angular.module('eee-c.angularBindPolymer', []).
directive('bindPolymer', function($q, $timeout) {
  // Yesterday's directive definition here...
});
I check those in locally and am ready to try them back in the application from which this is being extracted.

So, back in the bower.json file from the original project, I add my local Git repository in the list of dependencies:
{
  "name": "angular_example",
  // ...
  "dependencies": {
    "angular": "~1.2.9",
    "polymer": "~0.1.3",
    "angular-route": "~1.2.9",
    "angular-bind-polymer": "/home/chris/repos/angular-bind-polymer/"
  }
}
In the application directory, I bower install to get my new module:
➜  js git:(master) ✗ bower install
bower angular-bind-polymer#*       not-cached /home/chris/repos/angular-bind-polymer#*
bower angular-bind-polymer#*          resolve /home/chris/repos/angular-bind-polymer#*
bower angular-bind-polymer#*         checkout master
bower angular-bind-polymer#*         resolved /home/chris/repos/angular-bind-polymer#7bcc2d673d
bower angular#~1.2.9                   cached git://github.com/angular/bower-angular.git#1.2.9
bower angular#~1.2.9                 validate 1.2.9 against git://github.com/angular/bower-angular.git#~1.2.9
bower angular#~1.2.9                      new version for git://github.com/angular/bower-angular.git#~1.2.9
bower angular#~1.2.9                  resolve git://github.com/angular/bower-angular.git#~1.2.9
bower angular#~1.2.9                 download https://github.com/angular/bower-angular/archive/v1.2.11-build.2195+sha.29432ff.tar.gz
bower angular#~1.2.9                  extract archive.tar.gz
bower angular#~1.2.9                 resolved git://github.com/angular/bower-angular.git#1.2.11-build.2195+sha.29432ff
bower angular-bind-polymer#*          install angular-bind-polymer#7bcc2d673d

angular-bind-polymer#7bcc2d673d bower_components/angular-bind-polymer
└── angular#1.2.9
Next, I need to update the web page that holds my Angular application so that, after loading Polymer, Angular, and other related sources, it loads my new package:
    <script src="bower_components/platform/platform.js"></script>
    <link rel="import" href="elements/x-pizza.html">

    <script src="bower_components/angular/angular.min.js"></script>
    <script src="bower_components/angular-route/angular-route.min.js"></script>
    <script src="bower_components/angular-bind-polymer/angular_bind_polymer.js"></script>
Finally, I remove the directive code from my Angular application and, in its place, add my new module:
var pizzaStoreApp = angular.module('pizzaStoreApp', [
  'ngRoute',
  'eee-c.angularBindPolymer'
]);

pizzaStoreApp.config(['$routeProvider',
  // Routing stuff here...
]);
And, with that, I am done! I have successfully created a working Angular module in a Git repository and used that repository to install and use that Angular module.

All that is left at this point is to register the package with bower. First I tag (and push to GitHub):
➜  angular-bind-polymer git:(master) git tag -a v0.0.1 -m "Tag version 0.0.1" 
➜  angular-bind-polymer git:(master) git push --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 171 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:eee-c/angular-bind-polymer.git
 * [new tag]         v0.0.1 -> v0.0.1
Then I register:
➜  angular-bind-polymer git:(master) bower register angular-bind-polymer https://github.com/eee-c/angular-bind-polymer.git
bower                          convert Converted https://github.com/eee-c/angular-bind-polymer.git to git://github.com/eee-c/angular-bind-polymer.git
bower angular-bind-polymer#*   resolve git://github.com/eee-c/angular-bind-polymer.git#*
bower angular-bind-polymer#*  download https://github.com/eee-c/angular-bind-polymer/archive/v0.0.1.tar.gz
bower angular-bind-polymer#*   extract archive.tar.gz
bower angular-bind-polymer#*  resolved git://github.com/eee-c/angular-bind-polymer.git#0.0.1
[?] Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue? Yes
bower angular-bind-polymer    register git://github.com/eee-c/angular-bind-polymer.git

Package angular-bind-polymer registered successfully!
All valid semver tags on git://github.com/eee-c/angular-bind-polymer.git will be available as versions.
To publish a new version, just release a valid semver tag.

Run bower info angular-bind-polymer to list the available versions
And I'm done!

Day #1,013

Thursday, January 30, 2014

Generalizing My Angular Solution for Polymer


I am undecided on how to present Polymer integration with AngularJS in Patterns in Polymer. As of last night, I have it working nicely in the JavaScript versions of both libraries. The problem with which I am faced is that it is much easier and cleaner to establish double binding in the Dart versions of the libraries.

The ease in Dart is entirely thanks to the angular_node_bind library. If there is an equivalent in the JavaScript world, I have not found it. This leaves me with the dilemma of either writing a similar library myself in JavaScript or describing how to write an equivalent directive in Dart.

To keep my options open, tonight I will try my hand at polymer-bind, which, if I can manage it, would be an Angular directive that establishes a double bound attribute in a Polymer, à la:
<pre ng-bind="pizzaState"></pre>
<p>
  <x-pizza bind-polymer state="{{pizzaState}}"></x-pizza>
</p>
I already have a directive that works specifically for the state attribute on a Polymer and a pizzaState scope variable. Once the Polymer is ready, then the directive establishes a watcher for that attribute / variable pair:
directive('bindPolymer', function($q, $timeout) {
  return {
    restrict: 'A',
    link: function(scope, element) {
      // ...
      // When Polymer is ready, establish the bound variable watch
      onPolymerReady().
        then(function(){
          // Mutation observer here to force Angular $apply when attribute changes...
          scope.$watch(
            function() {return element.attr('state');},
            function(value) {
              scope.pizzaState = value;
            }
          );
        });
    }
  };
});
I need something a bit more generalized than that. Specifically, I need to map all of the attributes with curly brace bindings to the variable names inside the curly braces:
directive('bindPolymer', function($q, $timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var attrMap = {};
      for (var prop in attrs.$attr) {
        if (prop != 'bindPolymer') {
          var _attr = attrs.$attr[prop];
          var _match = element.attr(_attr).match(/\{\{\s*(\w+)\s*\}\}/);
          if (_match) {
            attrMap[_attr] = _match[1];
          }
        }
      }
      // ...
    }
  };
});
Then I need to use that map to establish the necessary attribute watch that will update the variable in the current scope:
directive('bindPolymer', function($q, $timeout) {
  return {
    restrict: 'A',
    link: function(scope, element) {
      // ...
      // When Polymer is ready, establish the bound variable watch
      onPolymerReady().
        then(function(){
          // Mutation observer here to force Angular $apply when attribute changes...
          for (var _attr in attrMap) {
            scope.$watch(
              function() {return element.attr(_attr);},
              function(value) {
                scope[attrMap[_attr]] = value;
              }
            );
          }
        });
    }
  };
});
And that works just fine. It is definitely nice starting from a specific, working case.

All that is left from there is to extract this directive out into a separate Bower repository.


Day #1,012

I Blogged for 1,000+ Days Straight and All I Got Was…


I have blogged now for more than 1,000 days straight. Every day. No holidays. No sick days. 2+ years. Every. Single. Day.

At some point, I will look back on all of this and write up a proper retrospective on what this has meant to me—both professionally and personally. For now, it seemed a sufficiently significant milestone that I ought to take a moment to acknowledge it.

The last day that I did not blog was April 24, 2011. Since April 25 of that year, I started every day with a question to which I did not know the answer and did my best to answer it. I did not always succeed in answering that question (I couldn't get mod_spdy working on my very first day!), but I always made a good faith effort. More often than not, I advanced my knowledge significantly. When I did not, I learned enough to rephrase the question for the next day.

That approach worked. Not only did I learn, but these research notes would serve as the basis for five books (well 4½).

The Books

The five books that have grown from these efforts are:


I can honestly say that I love each of those books. The SPDY Book was my first and remains, to the best of my knowledge, the only technical networking book to use crayon illustrations. Recipes with Backbone was the first that I co-authored—I learned so much working closely with my friend, the wonderful Nick Gauthier. Dart for Hipsters, of course, introduced me to the world of Dart, which I have not left. I tried my hand at giving back with 3D Game Programming for Kids, hoping to introduce a next generation to programming in the fashion that I learned to code (albeit with cooler graphics). Finally, Patterns in Polymer is, to the best of my knowledge, the first book to be simultaneously translated into two different programming languages (JavaScript and Dart).

Naturally, I learned a ton on this epic adventure—there seem to be an infinite number of fun technologies and cool communities out there. But what I appreciate the most is the mundane, not the epic.

The Mundane Epic

I did not make it through 1,000 blog posts and 5 books with insane effort or burning passion. I lack intense passion. What I do have is dull, plodding passion. I'm pretty sure dull, plodding passion always wins. Let's call a burning passion what it really is: infatuation. And infatuation will easily exhaust anything it touches.

In many ways, I find happiness an interesting comparison. The Happiness Hypothesis the two kinds of passion thusly:



The big spike of infatuation sure has its appeal and is a ton of fun. But it is over so quickly that the total amount of happiness / production simply can not compare with total area under the happiness that comes from a serene commitment to something or somebody.

Do Not Try This At Home

Look, I am not trying to start a trend or a movement here. I found something that works for me. I fully acknowledge that I start from the lowest difficulty setting.

This was not about elevating myself about others. It is simply about pushing myself to see what would happen if I tried to accomplish something crazy. Maybe this exact approach would work for someone else, but that's not really the point. The point is, if at all possible, to find that dull, plodding commitment that will bring about real happiness.

Speaking of happiness, I'm not sure this would be possible as a first priority in life. My wife and three (soon to be four) kids remain my first priority. I'm lucky to have overlap: my wife is my first editor on all of my books and served as QA for the 3D Kids book, while my kids served as guinea pigs. Family time (vacations, school and sports activities, meals, etc) is sacrosanct. Even if I have a deadline for this, I do what I can to ensure that I carve out time for my first priority.

The Dullest Man in the World

So maybe I am trying to start something. I would like to be recognized as the dullest, most plodding person in the world. Because it earned me a ton.

I blogged for 1,000+ days and all I got was heaps of knowledge and a little extra happiness in this life. And I'd do it all again in a heartbeat. Because I am just that dull.

Wednesday, January 29, 2014

Watching Polymer Attributes


I grow obsessed.

Double binding of AngularJS and Polymer attributes remains unsatisfying. Binding attributes works just when Angular is pushing changes to Polymer (there is even a nifty screencast). But if Polymer updates the same attribute, AngularJS will ignore it.

I am binding my <x-pizza> Polymer with the usual curly braces:
<pre ng-bind="pizzaState"></pre>
<p>
  <x-pizza polymer-directive state="{{pizzaState}}"></x-pizza>
</p>
Since Angular double-binding does not work out of the box with Polymer elements like <x-pizza>, I have resorted to writing that custom polymer-directive in Angular. I stayed up late last night and, instead of writing Patterns in Polymer, I came up with this version of the directive which works pretty darn well:
directive('polymerDirective', function($timeout) {
  return {
    restrict: 'A',
    link: function(scope, element) {
      // Always get updated Polymer element
      function polymer() {
        return element.parent().children()[0];
      }

      // Helper to wait for Polymer to expose the observe property
      function onPolymerReady(fn) {
        polymer().observe ?
          fn() :
          $timeout(function(){onPolymerReady(fn);}, 10);
      }

      // When Polymer is ready, establish the bound variable watch
      onPolymerReady(function(){
        // When Polymer sees a change to the bound variable,
        // $apply / $digest the changes here in Angular
        polymer().observe['state'] = function(){scope.$apply()};
        scope.$watch(
          function() {return element.attr('state');},
          function(value) {
            scope.pizzaState = value;
          }
        );
      });
    }
  };
});
There are three pieces in there that make this work. First, I need direct access to the Polymer element, not the Angular wrapped version of the element. Second, the Polymer is not ready for this directive until it has the observe property. The onPolymerReady() function polls for that property every 10 milliseconds until it exists, then calls the supplied callback. Lastly, the actual directive link goes inside that callback—when the Polymer is ready, I watch for changes on the state attribute, updating the bound variable in the current scope when it changes.

And that works fairly well. Within no more than 10 milliseconds of the Polymer being decorated with the usual methods and properties, Angular is now able to see changes and bind to changes in the Polymer:



And, if I add an ng-model, I find that Angular can still push changes down to the Polymer:



Two-way binding of a Polymer with minimal fuss. There is just one teeny, tiny problem. The observe property is probably not ideal for general usage:
polymer().observe['state'] = function(){scope.$apply()};
The observe property in Polymer is a cheap way to establish change listeners on properties in Polymer. The drawback to it is that (currently), it prevents named change listeners from firing inside the Polymer. That is, if my Polymer relied on a change listener for the state attribute:
Polymer('x-pizza', {
  // ...
  stateChanged: function(oldValue, newValue) {
     // Something very important to the internal workings of the Polymer goes here...
  },
  // ..
});
Then the very act of preventing this merely by setting observe['state'] would prevent that very important update from occurring. Not cool.

Instead of doing that, I think it best to use a bit of the Polymer platform. In this case, I use the MutationObserver polyfill:
          var observer = new MutationObserver(function() {scope.$apply()});
          observer.observe(polymer(), {attributes: true});
Mutation observers are useful for watching for any kind of change on an Element. It is possible to filter the watch for changes on an element, its children, or as I have done here, its attributes. Whenever any kind of change or changes is observed, the MutationObserver's callback is invoked.

And that does the trick nicely. Now I am safe in the knowledge that I am not interfering with any inner workings of my Polymer, but am still seeing the attribute change when it is supposed to. It would be nice if Angular and Polymer understood each other sufficiently to do this on their own, but until that happens, I am happy to have a seemingly stable solution to the problem.


Day #1,011

Tuesday, January 28, 2014

Trying Recompiling Angular Directives to see Polymer Changes


I am still trying to get my AngularJS application to bind to my <x-pizza> Polymer element. It is fairly easy to push changes from Angular down into my Polymer via normal binding, but two way binding thus far has eluded me.

Actually, after last night, I have a solution that relies on an Angular directive that triggers its own $apply, but I would rather just have Angular recognize that $apply needs to be called during its normal course of operations.

Today, I am thinking that Angular is not aware of my Polymer's attribute changing because the attribute is redefined after Angular finishes binding. So I try recompiling:
directive('polymerDirective', function($timeout, $compile) {
  return {
    restrict: 'A',
    link : function(scope, element, attrs) {
      element.removeAttr('polymer-directive');
      element.attr('delayed-polymer','');
      $timeout(
        function(){
            //debugger
          var el = element.parent().children()[0];
          $compile(el)(scope);
        },
        500
      );
    }
  };

After half a second, I recompile the attribute with a new directive:
directive('delayedPolymer', function() {
  return {
    restrict: 'A',
    link : function(scope, element, attrs) {
      console.log('yo ' + attrs.state);
      scope.$watch(
        'attrs.state',
        function(value) {
          console.log('change seen');
          scope.pizzaState = value;
        }
      );
    }
  };
}).
But that still does not quite work. Even delaying the application of the directive until Polymer has done its initialization thing does not enable Angular to watch changes on the Polymer's attribute. It seems that last night's solution may be the best that I can do for now.

Day #1,010

Monday, January 27, 2014

Better Angular $apply and Polymer


OK. One more crack at it. Just one more.

I continue to struggle getting AngularJS to double bind variables from Polymer. I am working on an <x-pizza> Polymer that builds an SVG representation of a pizza:



Additionally, I have it publishing the current state of the pizza in an state attribute so that the element ends up looking something like:
<x-pizza state="pepperoni,green peppers
sausage
sausage"><x-pizza>
In the Angular application, I have a directive that tries to bind that state so that it can be reflected elsewhere in the application:
<pre ng-bind="pizzaState"></pre>
<p>
  <x-pizza polymer-directive state="{{pizzaState}}"></x-pizza>
</p>
But Angular refuses to bind that variable—not without some manual intervention.

In my custom polymer-directive, I would expect that I can $observe() or $watch() for changes on attrs.state, but that does me no good. However Angular is compiling the attributes, it is not able to see subsequent updates from Polymer.

Actually, it can read the updated attributes via element.attr('state'), but it cannot listen for changes from Polymer. So I exploited that last night by setting a regular Angular $interval to $apply() the usual Angular event loop—the same event loop that a change in a normal element would trigger automatically. And that worked, save for either the delay in the $interval() or higher than normal load as the $interval() reran $apply().

So tonight, I try for something a little less broad. Instead of re-rerunning $apply(), I only do so when there is an event in the Polymer that contains my directive:
var pizzaStoreApp = angular.module('pizzaStoreApp', [ /* ... */ ]).
directive('polymerDirective', function($interval, $timeout) {
  return {
    restrict: 'A',
    link : function(scope, element, attrs) {
      scope.$watch(
        function() {
          return element.attr('state');
        },
        function(value) {
          scope.pizzaState = value;
        }
      );

      element.on('click keyup', function(){
        scope.$apply();
      });
      // $interval(function(){},500);
    }
  };
});
But that does not work. What is interesting about that not working is that the element—my <x-pizza> Polymer—does not appear to be generating events that Angular's element can see. But it is generating events that the rest of the page sees. And it is not as if Angular is looking at the wrong element—after all, I can get the current attribute value through element. Somehow, Polymer seems to be confusing part of Angular's element and attr. I hate to put out a solution in Patterns in Polymer that involves such flakiness, but it is starting to seem like I am going to have to accept some level of oddness.

Anyhow, even though I cannot listen for events on element, I can listen for events on element.parent():
      // ...
      element.parent().on('click keyup', function(){
        scope.$apply();
      });
      // ...
That works fairly well. Whenever there is a click or keyup event in my Polymer, the Angular directive runs through the $apply() / $digest() loop, which includes the watcher for changes to element.attr('state').

I do find that this works best if I yield the browser event loop for one cycle, giving the Polymer a chance to fully update its internal state as well as its attribute. The easiest way to accomplish this in Angular is with a simple $timeout for zero seconds—it doesn't even need to do anything, just wait:
      // ...
      element.parent().on('click keyup', function(){
        $interval(function(){},500);
      });
      // ...
With that, I have my Angular application more or less updating only when changes might reasonably occur in my Polymer:



About the only thing that does not work in this scenario is if the Polymer were to generate some kind of update in response to something aside from a user action. I do not see anyway around this other than listening for some kind of custom change event or by accepting some delay in notification to the Angular application when using an $interval. This is pretty darn close, but… I may actually take one more day to try to solve this.

Day #1,009

Sunday, January 26, 2014

Holy Cow: Binding Angular to Polymer Take 2


I really hoped to finish writing the SVG chapter in Patterns in Polymer last night. As it turns out, AngularJS had other ideas. Like not working at all like I expected.

Last night's question was how can I bind an AngularJS application so that it has access to data inside a Polymer? I have already done this in the Dart versions of both libraries, so I thought this would be an easy question to answer in the JavaScript equivalents. Thanks to angular_node_bind in Dart, I could use square brackets to establish two-way binding between Polymer and Angular:
<h3>Oooh! Let's make beautiful pizza together</h3>
<pre>{{ pizza }}</pre>
<p>
  <x-pizza pizzaState="[[ pizza ]]"></x-pizza>
</p>
That did not work in JavaScript. I note that there was a long discussion on the subject some time ago—and the syntax for Dart's angular_node_bind seems to have been at least partially inspired from that post. But, if there a JavaScript equivalent out there, my Google-fu fails me.

I next tried to write my own directive to accomplish this. Even if it is not a generalized solution (and I still suspect there is already one out there somewhere), this should not be too difficult, right? I write the JavaScript version as:
<h3>Oooh! Let's make beautiful pizza together</h3>
<pre ng-bind="state"></pre>
<p>
  <x-pizza polymer-directive state="state"></x-pizza>
</p>
The state variable in both cases can be two-way bound if that polymer-directive scopes the attribute with =:
var pizzaStoreApp = angular.module('pizzaStoreApp', [ /* Angular modules here... */ ]).
directive('polymerDirective', function($interval) {
  return {
    restrict: 'A',
    scope: { state: '=' },
    // ...
  };
});
That should make an attribute directive (“A”) that binds the value of state in the local scope with the value of the same name in the parent scope. From there, I can establish a simple watch on the state attribute from the <x-pizza> Polymer:
directive('polymerDirective', function($interval) {
  return {
    restrict: 'A',
    scope: { state: '=' },
    link : function(scope, element, attrs) {
      scope.$watch(
        function() { // The value being watched..
          return element.attr('state');
        },
        function(value) { // What to do when the value changes ...
          scope.state = value;
        }
      );
    }
  };
});
But darn it, that does not work. The <x-pizza> Polymer is correctly updating the value of the state attribute, but Angular is not acknowledging the change:



It turns out that Angular is not calling the $digest event loop, and so the $watch is never being evaluated. If I add an <input ng-model>—even one that is not tied to a model used anywhere else—then typing in that input field will invoke $digest, which, in turn, calls my $watch:



So my ultimate solution is to set an interval in my digest. By default, $interval will evaluate the digest loop, so the interval function does not need to do anything:
directive('polymerDirective', function($interval) {
  return {
    restrict: 'A',
    scope: { state: '=' },
    link : function(scope, element, attrs) {
      scope.$watch(
        function() {
          return element.attr('state');
        },
        function(value) {
          scope.state = value;
        }
      );

      $interval(function(){},500);
    }
  };
});
And that seems to do the trick:



But is that the best way to do this?


Day #1,008

Saturday, January 25, 2014

Binding Angular to Polymer


I am mildly concerned that I am less than a month away from the release of Patterns in Polymer while still having so many outstanding questions. That said, all I can do is answer one question tonight and hope the rest take care of themselves in the days to come. And tonight's question is, how do I get data out of Polymer?

I already answered this question in the Dart version of Polymer.dart. Hopefully the answer in JavaScript will be similarly easy.

This turns out to be not quite so easy, however. I try the obvious approach—binding Angular variables:
<h3>Oooh! Let's make beautiful pizza together</h3>

<pre ng-bind="value">
</pre>

<p>
  <x-pizza state="{{value}}"></x-pizza>
</p>
But I wind up with nothing in the <pre> element even though the state attribute in <x-pizza> is definitely updated:



And I have to admit that I am stumped here. No matter what I try in the Polymer use (ng-state, ng-attr-state, etc). I cannot seem to get Angular to recognize this as an attribute—at least not as an attribute that is being updated.

I know that this works when changes are pushed down into Polymer. There is a nice little demo that describes it. In fact, I can see this here. If I add an ng-model INPUT element, I can update the value of the pizza state down in the Polymer. But when the Polymer in turn updates its state, Angular is not seeing the change.

Bother. Even trying to set $scope.watch() on the attribute seems to have no effect. It seems that I may have to dig further than I would have liked into this.

Day #1,007

Friday, January 24, 2014

Getting Started with Protractor (But Not Really)


So Protractor: do I need it? Well, since it has been announced as the official end-to-end testing framework for AngularJS, I probably need it. But do I need it for Polymer and will it prove useful for Patterns in Polymer?

I think today I will explore that by using Protractor to test last night's Angular + Polymer + SVG application:



I start by installing Protractor with npm:
$ npm install -g protractor
...
/home/chris/local/node-v0.10.20/bin/protractor -> /home/chris/local/node-v0.10.20/lib/node_modules/protractor/bin/protractor
/home/chris/local/node-v0.10.20/bin/webdriver-manager -> /home/chris/local/node-v0.10.20/lib/node_modules/protractor/bin/webdriver-manager
protractor@0.17.0 /home/chris/local/node-v0.10.20/lib/node_modules/protractor
├── saucelabs@0.1.1
├── minijasminenode@0.2.7
├── adm-zip@0.4.3
├── optimist@0.6.0 (wordwrap@0.0.2, minimist@0.0.5)
├── glob@3.2.8 (inherits@2.0.1, minimatch@0.2.14)
└── selenium-webdriver@2.39.0
Protractor does not seem to come with slick setup and configuration initializers just yet, but it does have example config that I can copy from the installation directory:
$ mkdir protractor
$ cp /home/chris/local/node-v0.10.20/lib/node_modules/protractor/example/* protractor/
I am going to test with the Chrome driver tonight, so I download:
$ wget http://chromedriver.storage.googleapis.com/2.8/chromedriver_linux64.zip
And install it:
$ unzip chromedriver_linux64.zip
$ mv chromedriver protractor/
With that, I can run the example Protractor test:
$ protractor protractor/chromeOnlyConf.js                                     
Using ChromeDriver directly...
...

Finished in 10.63 seconds
3 tests, 5 assertions, 0 failures
To test my own application, I start a protractor/conf.js for my current angular application:
exports.config = {
  chromeOnly: true,
  chromeDriver: 'chromedriver',
  capabilities: {
    'browserName': 'chrome'
  },
  specs: ['pizza_spec.js'],
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000
  }
};
But that is about as far as I get. I try what I think is a simple test to click on the <a> tag to get to the next page in my app where I can verify that that <x-pizza> tag is present:
describe('pizza store', function() {
  beforeEach(function() {
    browser.get('http://localhost:8000');
  });

  describe('pizza builder', function() {
    beforeEach(function() {
      var finder = by.id('mk-custom');
      var el = element(finder);
      el.click();
    });

    it('should have an <x-pizza> Polymer', function() {
      var el = by.css('x-pizza');
      expect(browser.isElementPresent(el)).toBe(true);
    });
  });
});
Bu no matter what I try, I get stale element errors:
protractor protractor/conf.js
Using ChromeDriver directly...
F

Failures:  

  1) pizza store pizza builder should have an <x-pizza> Polymer
   Message:
     StaleElementReferenceError: stale element reference: element is not attached to the page document
  (Session info: chrome=34.0.1797.2)
  (Driver info: chromedriver=2.8.240825,platform=Linux 3.5.0-18-generic x86_64)
   Stacktrace:
     StaleElementReferenceError: stale element reference: element is not attached to the page document
  (Session info: chrome=34.0.1797.2)
  (Driver info: chromedriver=2.8.240825,platform=Linux 3.5.0-18-generic x86_64)
==== async task ====
WebElement.click()
    at element.(anonymous function) [as click] (/home/chris/local/node-v0.10.20/lib/node_modules/protractor/lib/protractor.js:440:32)
    at /home/chris/local/node-v0.10.20/lib/node_modules/protractor/lib/protractor.js:89:34
I suspect this has something to do with my use of partials—especially on the start page, but I'll be darned if I can figure out how to convince Protractor that there really is a clickable link tag.

Bother. I may try this again tomorrow, but I cannot afford too much time. There are many more Polymer things to research before I am done.


Day #1,006

Thursday, January 23, 2014

Using Polymer Tags in an AngularJS Application (with Routing)


The question I would like to answer today is how to go about getting a Polymer working inside of an AngularJS application. I already know how to do this in the Dart version of both libraries, so hopefully this will prove to be an easy answer.

They are never easy answers.

After last night, I have an <x-pizza> Polymer that builds pizzas:



Let's see if I can use that Polymer in an Angular pizza shop application. As with the Dart version, I will try to get this working with a simple, routing-only Angular application. In my mind at least, including the routing ensures that I am exercising a decent amount of the library. That goes against my usual approach of limiting the number of moving parts, but without some interesting bits of the library in place, I feel as though it is too easy to think I have it legitimately incorporated.

I start with a Bower install of Angular: bower install angular --save. I could have used Angular from the CDN, but I am already using Bower for Polymer so I stay consistent. For the routing, I also need to bower install angular-route --save.

That leaves me with a bower.json with the following dependencies:
{
  "name": "angular_example",
  // ...
  "dependencies": {
    "angular": "~1.2.9",
    "polymer": "~0.1.3",
    "angular-route": "~1.2.9"
  }
}
One thing that the JavaScript world makes easier than the Dart equivalent is the ability to run any number of scripts and libraries at the same time. There is a cost to doing so, of course, but in this case it helps.

In my main page, I include everything. I include the Polymer library. I include the Polymer definition from last night. I include Angular and the Angular routing library. I include the Angular application. And I point the page to the Angular application and include an ng-view tag to hold the application:
<!doctype html>
<html ng-app="pizzaStoreApp">
  <head>
    <title>Pizza!</title>
    <script src="bower_components/platform/platform.js"></script>
    <link rel="import" href="elements/x-pizza.html">
    <script src="bower_components/angular/angular.min.js"></script>
    <script src="bower_components/angular-route/angular-route.min.js"></script>
    <script src="scripts/pizza_store.js"></script>
  </head>
  <body>
    <div class="container">
      <h1>JavaScript Pizza Shoppe</h1>
      <div ng-view></div>
    </div>
  </body>
</html>
The ng-app attribute on the <html> tag ties this page to an Angular application named pizzaStoreApp. I define that in scripts/pizza_store.js as a simple router-only Angular application:
'ngRoute'
]);

pizzaStoreApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/home', {
        templateUrl: 'scripts/partials/home.html'
      }).
      when('/pizza/custom', {
        templateUrl: 'scripts/partials/custom.html'
      }).
      otherwise({
        redirectTo: '/home'
      });
  }
]);
The two partials are simple HTML samples. I use last night's SVG-based Polymer in the custom.html partial:
<h3>Oooh! Let's make beautiful pizza together</h3>
<p>
  <x-pizza></x-pizza>
</p>
And that turns out to be all that is needed:



That was pleasantly easy. Much of that was made easier for having already done it in Dart, but I do think the JavaScript version of Angular remains slightly more polished than its Dart cousin. Regardless, I now have Angular and Polymer playing nicely together in both JavaScript and Dart.


Day #1,005

Wednesday, January 22, 2014

JavaScript Polymer SVG: Testing with Jasmine


OK tonight I go back to get SVG working with my JavaScript flavored <x-pizza> element. No more of the sweet, sweet nectar of Dart—I will eat my vegetables!

I kid, of course, I still love JavaScript. That love is not rewarded with a nice SVG API, however. In Dart, I could create the various elements that made up the pizza and its toppings with code like:
  _svgPepperoni() =>
    new CircleElement()..attributes = {'r': '10', 'fill': 'red'};
It seems that JavaScript lacks a constructor for circle SVG elements, leaving me to write much longer code like:
  _svgPepperoni: function() {
    var el = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    el.setAttribute('r', '10');
    el.setAttribute('fill', 'red');
    return el;
  }
I make a bunch of changes along those lines (for other toppings and groups of toppings). I also have to manually convert a lot of Dart code into JS:
  • removing method cascades
  • changing innerHtml to the crazy innerHTML
  • add the this keyword absolutely everywhere
  • add the that variable where scope is an issue
  • Remove string interpolation in “favor” of plussing strings together.
It's a pain.

But it works:



I have been a little remiss in my testing, so I pick back up here with a Karma / Jasmine test. I have to update the list of files being tested and/or served to include not only my <x-pizza> elements in the elements directory, but I also need to be sure to grab the bower directory for Polymer:
...
    // list of files / patterns to load in the browser
    files: [
      'test/PolymerSetup.js',
      {pattern: 'elements/**', included: false, served: true},
      {pattern: 'bower_components/**', included: false, served: true},
      'test/**/*Spec.js'
    ],
...
My test setup is similar to what I have used in the past, updated only for new file names.

As for the test itself, I create a setup that adds <x-pizza> to the test page:
describe('<x-pizza>', function(){
  var container;

  beforeEach(function(){
    container = document.createElement("div");
    container.innerHTML = '<x-pizza></x-pizza>';
    document.body.appendChild(container);
    waits(0); // One event loop for elements to register in Polymer
  });

  afterEach(function(){
    document.body.removeChild(container);
  });

  // Tests here...
});
Then I can test the contents of the SVG element on the Polymer's shadow root:
  describe('defaults', function(){
    it('to a blank pizza', function() {
      var el = document.querySelector('x-pizza');
      var svg = el.shadowRoot.querySelector('svg');
      expect(svg.innerHTML).toContain('circle cx="150" cy="150" r="150" fill="tan"');
    });
  });
For now, I just verify that the SVG element is present and that it contains a dynamically generated <circle> element with all of the right attributes.

And it works:
INFO [watcher]: Changed file "/home/chris/repos/polymer-book/play/svg/js/test/XPizzaSpec.js".
Chrome 34.0.1797 (Linux): Executed 1 of 1 SUCCESS (0.701 secs / 0.403 secs)
Though it is better than nothing, that is a frail test. I ought to (and will before it is added to support a Patterns in Polymer chapter) query for the circle element and set expectations on it attributes rather than hoping that attributes retain their order. Still, I am happy to have gotten this converted over in relatively short order—better still to have actual tests to verify that it does what I think.


Day #1,004

Tuesday, January 21, 2014

Dynamically Binding Polymer Values into Angular Applications


Must. Stop. Dart.

I am getting too far ahead of myself while researching Patterns in Polymer. For the most part, I try to keep the Dart and JavaScript investigation in sync. But recently I pushed straight through SVG and on into Angular research with Dart. I really need to work my way back to do both in JavaScript (and to write new chapters on both).

But darn it, Seth Ladd pointed out the angular_node_bind package and… ooh, shiny!

But really, I think that packages answers a need that I had for extracting data from my <x-pizza> Polymer for use in the containing the Angular application:



I start with the usual, adding angular_node_bind to the list of my application's dependendencies in pubspec.yaml:
name: angular_example
dependencies:
  angular: any
  polymer: any
  angular_node_bind: any
dev_dependencies:
  unittest: any
transformers:
- polymer:
    entry_points:
    - web/index.html
While reading through the angular_node_bind example code, I notice an alternate syntax for initializing a Polymer-powered Angular application. After last night, I already know that I have to manually start the Polymer platform with initPolymer() in my application's main() entry point:
main() {
  initPolymer();

  var store = new AngularModule()
    ..type(RouteInitializer, implementedBy: StoreRouter);

  ngBootstrap(module: store);
}
But it seems that it may be more proper to perform that initialization inside a Polymer run():
main() {
  initPolymer().run((){

    var store = new AngularModule()
      ..type(NodeBindModule)
      ..type(RouteInitializer, implementedBy: StoreRouter);

    ngBootstrap(module: store);
  });
}
Even better, the new Angular.dart way of doing things seems to be running those type() injects inside a proper constructor:
class StoreModule extends Module {
  StoreModule() {
    type(NodeBindDirective);
    type(RouteInitializer, implementedBy: StoreRouter);
  }
}

main() {
  initPolymer().run((){
    ngBootstrap(module: new StoreModule());
  });
}
However it is done, that should give me what I want: angular binding to my Polymer attributes. So I test this out in my customizing pizza page. The double square brackets should bind an expression for me:
<h3>Oooh! Let's make beautiful pizza together</h3>

<pre>[[ pizza ]]</pre>

<p>
  <x-pizza pizzaState="[[ pizza ]]"></x-pizza>
</p>
But, when I load the page up, I am getting a nice old stacktrace:
Class 'DynamicExpression' has no instance getter 'assignable'.

NoSuchMethodError : method not found: 'assignable'
Receiver: Instance of 'DynamicExpression'
Arguments: []

STACKTRACE:
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
#1      NodeBindDirective.NodeBindDirective (package:angular_node_bind/angular_node_bind.dart:61:24)
#2      _LocalClassMirror._invokeConstructor (dart:mirrors-patch/mirrors_impl.dart:795)
#3      _LocalClassMirror.newInstance (dart:mirrors-patch/mirrors_impl.dart:736)
#4      DynamicInjector.newInstanceOf (package:di/dynamic_injector.dart:44:35)
#5      _TypeProvider.get (package:di/module.dart:142:29)
#6      Injector._getInstanceByType.<anonymous closure> (package:di/injector.dart:118:31)
#7      _defaultCreationStrategy (package:di/module.dart:106:34)
#8      Injector._getInstanceByType (package:di/injector.dart:116:23)
#9      Injector._getInstanceByType (package:di/injector.dart:124:7)
#10     Injector.get (package:di/injector.dart:173:47)
...
And I cannot quite figure this one out.

Update: I was able to get this working with a simple change to angular_node_bind. With that, I can update my Polymer <x-pizza> and see the changes in my Angular application:



Phew! That's a load off my mind. With that, I think I am safe going back to JavaScript-ify this SVG / Angular application.


Day #1,003

Monday, January 20, 2014

Observable Polymers in Angular Applications


It seems that I may have been a tad premature in thinking that I had the Dart versions of Angular and Polymer working together. To be sure, most of it is working. The Angular routing it successfully navigating between a simple start page and the page that contains my Polymer. The Polymer is sufficiently registered that it shows up on that second page:



But that turns out to be the extent of it. Even though the Polymer is starting enough to display, none of its buttons and menus are doing what they are supposed to be doing: building a pizza. At first I suspected that Angular was somehome seizing control of the various template bindings. The answer turns out to be much more mundane.

For whatever reason, I continue to use two Polymer lifecycle methods, ready() and enteredView(), interchangeably. They are not interchangeable—the developers would not bothered to create them if they were. And, in fact, this seems to be the use case in which they distinguish themselves. When I normally develop a Polymer, it is the only thing on the page. The Polymer is “ready” in this case when the Polymer has entered the view.

In my Angular application, however, the Polymer is ready when it and the Angular code load on the first page. By the time the next Angular route is accessed, the Polymer has been ready, left the view (resulting in observers going away), and brought back without re-registering things. Happily, the solution is to use the correct lifecycle method:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  XPizza.created(): super.created();
  enteredView() {
    super.enteredView();
    model = new Pizza()
      ..changes.listen(updatePizzaState);

    updatePizzaState();
  }
  // ...
}
That gets me a little closer, but things are still not updating when I make changes to the underlying model in the Polymer. I suspect that this is yet another case of Observable not updating in raw Dart. When I work with plain old Polymer, I work around this problem with a Dart Pub transformer.

When I got started with this Angular and Polymer combination, I purposefully removed the transformer to reduce the number of moving parts. In an attempt to get Observables working again, I restore the transformer in pubspec.yaml:
name: angular_example
dependencies:
  angular: any
  polymer: any
dev_dependencies:
  unittest: any
transformers:
- polymer:
    entry_points: web/index.html
Now, when I start up pub serve, I get loads of errors:
➜  dart git:(master) ✗ pub serve
Serving angular_example on http://localhost:8080
[Warning from polymer (Linter) on angular_example|web/partials/custom.html]:
web/partials/custom.html:4:3: definition for Polymer element with tag name "x-pizza" not found.
[Warning from polymer (Linter) on angular_example|web/index.html]:
web/index.html:22:7: definition for Polymer element with tag name "ng-view" not found.
...
There are a bunch more, but I eventually realize that those are just the usual dart2js warnings and errors. Hopefully those are just what they seem—linter warnings that do not have any real bearing.

But when I load my Angular application, I receive a very worrisome error:
Exception: InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable. (Dartium)
Worrisome, but apparently not devastating: the application, including observable (and buildable) <x-pizza> elements, now works:



That is not quite the end of it as this does not appear to work when compiled to JavaScript, but I leave that puzzle for another day.



Day #1,002

Sunday, January 19, 2014

Day 1,001: Getting Started with Angular and Polymer (Dart)


Up today, I start experimenting with Angular.dart and Polymer.dart. For tonight, I would like to start with a simple Angular application and see what, if anything, I need to do in order to use my amazing <x-pizza> Polymer:



I actually need to go back and fix that Polymer up some, but I think the learning ground is more fertile at this point with Angular than with refactoring or converting to JavaScript. Still, I do need to do both before <x-pizza> is Patterns in Polymer worthy. Anyway…

Angular. I love it. I am probably a horrible person to ask an opinion on libraries and frameworks. Most people seem to be absolutely certain that some are better than others. I am unable to make decisions like that until I work with a library enough that it starts to affect how I think about other tools. By that time, I have almost always found some great use-cases for the tool at hand, leaving me hard pressed to dislike outright.

So, for a guy that co-authored Recipes with Backbone and who still loves coding in Backbone.js, I also love Angular. Mostly I am glad to know both as I think they have overlap, but also different use-cases.

The use case that I would like to explore in Angular tonight is an online pizza store. I have an <x-pizza> Polymer, which seems like it could be put to nice use throughout such an app.

I start with a pubspec.yaml that includes both the Angular and Polymer packages, but does not include the usual Polymer transformer:
name: angular_example
dependencies:
  angular: any
  polymer: any
dev_dependencies:
  unittest: any
# transformers:
# - polymer:
#     entry_points: web/index.html
I am unsure how the transformer would interact with Angular, so I leave that out of the equation tonight.

While working with raw Polymer, I have needed to include initialization code in the web page:
    <!-- Load component(s) -->
    <link rel="import" href="packages/angular_example/elements/x-pizza.html">
    <!-- Load Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>
I do not think that will work in an Angular application, which needs to spin itself up without another Dart script gumming up the works. I don't think that will work, but I am not positive. To find out for sure, I set up my page with both Angular and Polymer initialization (Angular stuff goes in main.dart):
<!DOCTYPE html>
<html ng-app lang="en">
  <head>
    <title>Pizza Store</title>

    <script type="application/dart" src="main.dart"></script>

    <!-- Load component(s) -->
    <link rel="import" href="packages/angular_example/elements/x-pizza.html">
    <!-- Load Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>
  </head>
  <body>
    <div class="container">
      <h1>Dart Bros. Pizza Shoppe</h1>
      <ng-view></ng-view>
    </div>
  </body>
</html>
But, when I load that page, I see the following in the console:
[ERROR] Only one Dart script tag allowed per document
Bother. But not too much of a bother.

Back when I was learning to test Polymer, I needed to initialize Polymer without using that script. That turned out to be pretty easy. Instead of exporting that one script, I import the Polymer packages into my main.dart Angular app and invoke initPolymer:
import 'package:polymer/polymer.dart';
import 'package:angular/angular.dart';
import 'package:angular/routing/module.dart';
import 'package:angular_example/store.dart';

main() {
  initPolymer();

  var store = new AngularModule()
    ..type(RouteInitializer, implementedBy: StoreRouter);

  ngBootstrap(module: store);
}
In addition to removing the export, I also need to ensure that the usual <link> imports of Polymer elements occur before the main.dart script:
<!DOCTYPE html>
<html ng-app lang="en">
  <head>
    <title>Pizza Store</title>
    <link rel="import" href="packages/angular_example/elements/x-pizza.html">
    <script type="application/dart" src="main.dart"></script>
  </head>
  <body>
    <div class="container">
      <h1>Dart Bros. Pizza Shoppe</h1>
      <ng-view></ng-view>
    </div>
  </body>
</html>
With that, I am ready to take a look at my Angular application. As I said, I am starting very simple here. So simple, in fact, that I have a router and nothing more. The router declares two pages: the default start page and the custom pizza builder page:
import 'package:angular/angular.dart';
import 'package:angular/routing/module.dart';

class StoreRouter implements RouteInitializer {
  Scope _scope;
  StoreRouter(this._scope);

  void init(Router router, ViewFactory view) {
    router.root
      ..addRoute(
          defaultRoute: true,
          name: 'start',
          enter: view('partials/home.html')
        )
      ..addRoute(
          name: 'custom-pizza',
          path: '/pizza/custom',
          enter: view('partials/custom.html')
        );
  }
}
I define my two partials. The home.html is a simple page that links to the route defined for building custom pizza:
<h3>This is the home of darty pizza</h3>

<p>
  Why not
 <a href="/pizza/custom">build your own, awesome pizza</a>!
</p>
When I first load the application, I see:



Similarly, I define the custom.html partial as:
<h3>Oooh! Let's make beautiful pizza together</h3>

<p>
  <x-pizza></x-pizza>
</p>
Which results in:



That was rather easy to get working! Of course, I have yet to do anything real with this. I am not taking advantage of any of Angular's features and would very much like to explore binding values from Polymers into Angular applications. But that is grist for another day. For tonight, I am quite happy with the progress so far.


Day #1,001

Saturday, January 18, 2014

Day 1000: Animated SVG in Polymer


For an ostensibly UI facing library, I have done almost no UI work while researching Patterns in Polymer. I think that speaks to the hidden power of coding with the library. Even so, it is a web based, UI library, so I ought to do some UI-like things. Enter last night's <x-pizza> tag—the SVG based pizza builder:



The pizza SVG in this Polymer is built by passing a “maker” function, which makes individual toppings (e.g. pepperoni), into add-topping methods:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  _addFirstHalfTopping(maker) {
    for (var i=0; i<20; i++) {
      var angle = 2 * PI * _rand.nextDouble();
      var u = _rand.nextDouble() + _rand.nextDouble();
      var distance = 125 * ((u < 1.0) ? u : 2-u);

      var topping = maker()
        ..attributes.addAll({
            'cx': "${150 - (distance * sin(angle)).abs()}",
            'cy': "${150 + (distance * cos(angle))}"
          });

      $['pizza-graphic'].append(topping);
    }
  }
  // ...
}
It is a little hard to randomly distribute things in a circle, but happily there is Stack Overflow, which is the source for most of that.

It is nice to see the pizza built and all, but I would like to give hungry buyers more of a sense of building their own pizzas. Animating the toppings coming in from the side and dropping onto the pizza should do that nicely. I have no idea if that is possible with SVG, but there is one way to find out...

I start by grouping the toppings in an SVG <g> element. It turns out that you cannot set cx and cy attributes on group elements. Instead you have to translate them in a transform (that's gonna be easy to remember):
  _addFirstHalfTopping(maker) {
    var group = new GElement()
      ..attributes = {'transform': 'translate(150,150)'};

    for (var i=0; i<20; i++) {
      var angle = 2 * PI * _rand.nextDouble();
      var u = _rand.nextDouble() + _rand.nextDouble();
      var distance = 125 * ((u < 1.0) ? u : 2-u);

      var topping = maker()
        ..attributes.addAll({
            'cx': "${-(distance * sin(angle)).abs()}",
            'cy': "${ (distance * cos(angle))}"
          });

      group.append(topping);
    }
    $['pizza-graphic'].append(group);
  }
I have my toppings grouped and can position them together. How about animating?

Unfortunately, the <animate*> tags do not seem to work too well when trying to dynamically start animations. The <animateMotion> tag almost works… some of the time… when you don't hit reload too fast or stare at the page funny:
  _addFirstHalfaTopping(maker) {
    // ...
    $['pizza-graphic'].append(group);
    group..append(
          new AnimateMotionElement()..attributes = {
            'from': '0, 150',
            'to':   '150, 150',
            'dur':  '3s',
            'fill': 'freeze'
          }
        );

  }
For whatever reason, that does not seem reliable and fails to work at all on Firefox. So it seems that I need to revisit my old friend requestAnimationFrame(). I have honestly been missing this since 3D Game Programming for Kids went to press, so I may be reaching for a golden hammer here. But I don't care, animation frames, which are functions that get called when the browser signals it is ready to paint, are cool.

It seems that Dart has a future-based take on animation frames. Given an animate() function, I can ask the browser to call it with window.animationFrame.then(animate). The function that animates pizza toppings sliding in from the side over the course of 1.5 seconds is then:
  _addFirstHalfaTopping(maker) {
    // ...
    $['pizza-graphic'].append(group);
    var start;
    int dur = 1500;
    animate(time) {
      if (start == null) start = time;
      if (time - start > dur) return;
      var x = 150 * (time - start) / dur;
      group.attributes['transform'] = 'translate(${x.toInt()}, 150)';

      window.animationFrame.then(animate);
    };
    window.animationFrame.then(animate);
  }
That does the trick. Just as with the JavaScript requestAnimationFrame(), I have to request the animate() function once and then recursively call it from within animate() afterwards to keep the animation running. The effect is a nice, smooth animation that starts with the toppings floating in from the side:



And settling down nicely:



For completeness' sake, I animate the toppings falling gently, like a mother putting a babe down to rest, at the end of the left-to-right animation:
  _addFirstHalfaTopping(maker) {
    // ...
    $['pizza-graphic'].append(group);
    var start_y;
    int dur_y = 500;
    animateY(time) {
      if (start_y == null) start_y = time;
      if (time - start_y > dur_y) return;

      var x = 150;
      var y = 140 + 10 * sin(0.5 * PI * (time - start_y) / dur_y);

      group.attributes['transform'] = 'translate(${x}, ${y.toInt()})';

      window.animationFrame.then(animateY);
    }

    var start_x;
    int dur_x = 1500;
    animateX(time) {
      if (start_x == null) start_x = time;
      if (time - start_x > dur_x) return window.animationFrame.then(animateY);
      // ...
    };

    window.animationFrame.then(animateX);
  }
My code has serious longer-than-my-arm code smell at this point, but it works!

I call it a night here. Up tomorrow either the JavaScript implementation of this SVG Polymer or, if that proves trivial, I will move on to playing with Angular and Polymer together.

Day #1000

Friday, January 17, 2014

Day 999: Polymer and SVG


I can't resist. The temptation to play around with SVG is simply too great and I am helpless before its wiles.
I really meant to start looking at incorporating Polymer elements in Angular. Perhaps tomorrow. Onto the SVG!

I have a pretty cool <x-pizza> Polymer that builds pizzas for ordering:



The problem, of course, is that the current pizza state is in the form of text. Saaaay! SVG can help with that!

I start by adding a blank SVG tag to my <x-pizza> template:
<polymer-element name="x-pizza">
  <template>
    <h2>Build Your Pizza</h2>

    <!-- <pre>{{pizzaState}}</pre> -->
    <div title="{{pizzaState}}">
      <svg version="1.1"
        baseProfile="full"
        id="pizza-graphic"
        style="display: block; margin: 10px auto"
        width="300" height="300"
        xmlns="http://www.w3.org/2000/svg">
      </svg>
    </div>
    <!-- ... -->
  </template>
  <script type="application/dart" src="x_pizza.dart"></script>
</polymer-element>
That creates a 300 by 300 blank SVG canvas on which to paint. I give it an ID so that I can readily look it up using the Polymer $ for automatic node finding.

I already have my Polymer updating the pizza state (text-only so far) when new items are selected from the various menus. To do so, the updatePizzaState() method is called by various change event handlers. I factor the old text-only code out into _updatePizzaText(). In addition to calling this method, I also have updatePizzaState() call my new, SVG powered _updateGraphic() method:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  updatePizzaState([_]) {
    _updateText();
    _updateGraphic();
  }

  _updateGraphic() {
    this.$['pizza-graphic'].innerHtml = '''
      <circle cx="150" cy="150" r="150" fill="tan" />
      <circle cx="150" cy="150" r="140" fill="darkred" />
      <circle cx="150" cy="150" r="135" fill="lightyellow" />
    ''';
  }
  // ...
}
There is not too much to _updateGraphic() so far. It adds three circles in the center of the 300 by 300 SVG element, each slightly smaller than the previous, each representing a different layer of the pizza (crust, sauce, and cheese). I use the $ node finder to ensure that I have the correct SVG element.

With that, I have SVG!



To add toppings, I need a generator for each of the supported toppings:
  _svgPepperoni() =>
    new CircleElement()..attributes = {'r': '10', 'fill': 'red'};
  _svgSausage() =>
    new CircleElement()..attributes = {'r': '3',  'fill': 'brown'};
  _svgGreenPepper() =>
    new CircleElement()..attributes = {'r': '10', 'fill': 'green'};
Next, I need a way to choose the appropriate SVG maker function given a string representing a topping:
  _toppingMaker(String topping) {
    if (topping == 'pepperoni') return _svgPepperoni;
    if (topping == 'sausage') return _svgSausage;
    if (topping == 'green peppers') return _svgGreenPepper;
  }
With that, I can iterate over each topping and add them to the pizza:
  _addWholeToppings() {
    model.wholeToppings.forEach((topping) {
      var maker = _toppingMaker(topping);
      _addWholeTopping(maker);
    });
  }
The maker now points to the appropriate generator function (e.g. _svgPepperoni). Armed with that, I can make 20 randomly placed toppings with:
  _addWholeTopping(maker) {
    var rand = new Random();
    for (var i=0; i<20; i++) {
      var topping = maker();
      topping.attributes
        ..['cx'] = "${150 + (90 * cos(PI * rand.nextDouble()))}"
        ..['cy'] = "${150 + (90 * cos(PI * rand.nextDouble()))}";
      $['pizza-graphic'].append(topping);
    }
  }
And that does the trick. The end result is:



So yeah, I need a better green pepper. And maybe some animation. And random placement probably isn't quite right. But it is definitely better than plain text. So, yay SVG!


Day #999

Thursday, January 16, 2014

Day 998: Binding to Model Changes in Polymer (Dart)


Tonight, I hope to better express what needs to update when the Pizza model changes in my <x-pizza> Polymer. The JavaScript version of Polymer has an observe block to do this, but I cannot find a Dart equivalent. I came up with a solution (and a pretty good one), but I do not know if it is the solution. And I must strive for the solution in Patterns in Polymer.

I currently have a simple model driven Polymer that updates the pizza state for display:



Sure, it could use some fancy graphics, but this is fine for illustration and exploration. When a human clicks the add topping buttons, the Polymer adds the selected ingredient to the model. By virtue of property change listeners, the change in the Pizza model results in an update to the current pizza state representation:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  XPizza.created(): super.created() {
    model = new Pizza()
      ..firstHalfToppings.changes.listen(updatePizzaState)
      ..secondHalfToppings.changes.listen(updatePizzaState)
      ..wholeToppings.changes.listen(updatePizzaState);
    // ...
  }
  // ...
}
Thanks to the magic of Dart method cascades, I can establish change listeners for multiple properties on my model.

That is nice and all, but the three listeners seem a tad redundant. Really, I would be happier to listen for any changes anywhere in the model—not just changes to those individual properties. Something like that might be expressed as:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  XPizza.created(): super.created() {
    model = new Pizza()
      ..changes.listen(updatePizzaState);
    // ...
  }
  // ...
}
I have to admit that this sort of feels like something that an Observable class ought to give me for free. That is, if any observable properties in an observable class change, then the instance changes too. But that is not the case, so I am going to need to manually do this for my Pizza class:
class Pizza extends Observable {
  ObservableList<String> firstHalfToppings = toObservable([]);
  ObservableList<String> secondHalfToppings = toObservable([]);
  ObservableList<String> wholeToppings = toObservable([]);
}
(I am not sure the word “observable” is in there enough)

Thankfully, manually notifying that the model has changed in Polymer is directly supported via the notifyChange() method. So, in the Pizza constructor, I listen to the change stream on the individual properties and, whenever such an event occurs, I notify the object itself that a change has occurred:
class Pizza extends Observable {
  ObservableList<String> firstHalfToppings = toObservable([]);
  ObservableList<String> secondHalfToppings = toObservable([]);
  ObservableList<String> wholeToppings = toObservable([]);

  Pizza() {
    firstHalfToppings.changes.listen((_)=> notifyChange(_));
    secondHalfToppings.changes.listen((_)=> notifyChange(_));
    wholeToppings.changes.listen((_)=> notifyChange(_));
  }
}
I think that is pretty close to the spirit of what I want to accomplish.

Still, I am surprised that there is nothing closer to observe blocks in the the JavaScript version of Polymer. These let me observe properties via dot notation, invoking the supplied callback when changes are observed:
  observe: {
    'model.firstHalfToppings': 'updatePizzaState',
    'model.secondHalfToppings': 'updatePizzaState',
    'model.wholeToppings': 'updatePizzaState'
  },
But if that exists, I am unable to find it.


Day #998