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

1 comment:

  1. Thanks for the fix Chris. I pushed the version of angular_node_bind with your fix to pub: http://pub.dartlang.org/packages/angular_node_bind

    ReplyDelete