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

No comments:

Post a Comment