Angular and Polymer Data Binding, Together!





Angular and Polymer, sitting in a DOM tree,
B-i-n-d-i-n-g.
First comes components,
Then comes elements,
Then comes the interop with the node dot bind.

Angular, a super heroic MVC framework, and Polymer, polyfills and enhancements for custom elements built on top of Web Components, can live harmoniously in the same app. This post shows you how to connect Angular-controlled components to Polymer-controlled elements via data binding. And we do it all in Dart.

Angular and Polymer


I get asked "Should I use Angular or Polymer?" a lot. My answer is, "Yes". That is, both libraries have distinct strengths, and you can use both in the same app.

Polymer excels at creating encapsulated custom elements. You can use those custom elements in any web app or web page, regardless if that app is built with Angular, Ember, etc. Angular excels at application engineering, with dependency injection, end-to-end testability, routing, and services.




Here are some features that Angular offers:
  • directives - kind of like mixins or traits for DOM nodes
  • dependency injection
  • testing support
  • routing
  • services
  • server communication
Here are some features that Polymer offers:
  • <polymer-element> - convenient way to declare custom elements
  • widgets
  • polyfills for new web platform features
  • encapsulation for the DOM
  • built on emerging web standards
There are some similar features between the two libraries. Both libraries implement a data binding solution (which we cover below). Angular is beginning to build on top of emerging web standards (like Shadow DOM). I expect that, over time, more and more of Angular will take advantage of the Web Components family of specifications.

Interop

We can interop Angular and Polymer via the DOM, as well as via data binding.

DOM interop


We've always been able to use the DOM for basic interop between custom elements and Angular. For example, setting an attribute on a custom element is a type of API interop. Simply creating the custom element and inserting it into the document is another type of interop. Polymer and Angular already interop at the DOM layer.

For example, here's an example of an Angular managed page that includes a Polymer element.



In the above code, Angular manages the binding of the cool variable in the HTML. When cool changes, everywhere you see {{cool}} also changes. Yes, even when bound into an attribute of a custom element!

The <my-element> is just a custom Polymer element encapsulates an input field and displays a value. Here's the code:


<polymer-element name="my-element">
  <template>
    <p>
      <input type="text" value="{{message}}"> Polymer binding: {{message}}
    </p>
  </template>
  <script type="application/dart" src="my_element.dart"></script>
</polymer-element>

The Angular code can set attributes on <my-element>, listen for DOM events from <my-element>, and of course even insert children elements inside of <my-element>. So in a sense, Angular can interop with Polymer elements just like any other DOM element.

However, there is an issue. Can you spot it in the animated GIF below?


Any changes to cool initiated from inside the Polymer element are not propagated back out into the outside DOM or Angular. We need real bi-directional data binding: Angular down into Polymer, and Polymer back out to Angular.

Data binding interop


Polymer manages data binding through a feature called Node.bind(). Node.bind() is a "new method added to all DOM nodes which instructs them to bind the named property to the data provided". Angular does not use Node.bind() out of the box, so Angular is unable to listen for changes that are initiated from Polymer.

Until now.

Justin Fagnani, an engineer on the Dart team, released angular_node_bind, a Dart package that bridges the Angular and Polymer worlds. It is an Angular module that can listen for Node.bind() changes and propagate the changes into Angular.

Justin explains why this package can help:

  • Node.bind() takes care of setting up the binding, including two-way bindings, eliminating the need for directives for every property for two-way bindings.
  • Custom elements that expose properties will be properly bound, again including two-way bindings. You can use the growing collection of custom element libraries in your Angular app.

To use angular_node_bind, add the following to your app's pubspec.yaml file:


name: angularpolymer
description: A demo of Angular and Polymer data binding.
dependencies:
  angular: any
  angular_node_bind: any
  browser: any
  polymer: any
transformers:
- polymer:
    entry_points: web/angularpolymer.html

Register the NodeBindModule with Angular:


import 'package:polymer/polymer.dart' show initPolymer;
import 'package:angular/angular.dart' show ngBootstrap;
import 'package:angular_node_bind/angular_node_bind.dart' show NodeBindModule;

void main() {
  initPolymer().run(() {
    ngBootstrap(module: new NodeBindModule());
  });
}

Finally, change the syntax used for binding into Polymer elements, from {{...}} to [[...]]:


<my-element message="[[cool]]"></my-element>

Notice the binding expression is now [[cool]] instead of {{cool}}. The angular_node_bind module looks for [[ ... ]] and wires up Node.bind().

Here is a little movie of how the app works with true bi-directional data binding between Polymer and Angular:



Notice how changes from Angular are reflected in the Polymer element, and how changes from within the Polymer element are reflected in the Angular code. Awesome!

Summary

You can use Polymer custom elements inside of an Angular app in at least two ways. Polymer elements are just like regular DOM elements, so they have attributes, emit events, and can contain children elements. Use Dart's angular_node_bind package to connect Polymer's data binding to Angular's data binding for true bi-directional data sharing.

Lovely, Angular and Polymer holding hands.

Get the source code

You can check out the source code mentioned in this post.
Post a Comment

Popular posts from this blog

  • Sponsor:  Register today for  New Game, the conference for HTML5 game developers . Learn from Mozilla, Opera, Google, Spil, Bocoup, Mandreel, Subsonic, Gamesalad, EA, Zynga, and others at this intimate and technically rich conference. Join us for two days of content from developers building HTML5 games today. Nov 1-2, 2011 in San Francisco.  Register now ! This is the second article in a Box2D series, following the Box2D Orientation article. The Box2DWeb port of Box2D contains a nice example to show off the basics of integrating physics simulations into your web app. This post will provide a walkthrough of the example, explaining the high level concepts and code. First, let's see the example in action. The code for the above is open source and available on GitHub. It was adapted from Box2DWeb's example . Animating Before we look at Box2D, it's important to understand how the above simulation is animated. You might think setInterval or setTimeout is
    Keep reading
  • In which I port a snazzy little JavaScript audio web app to Dart , discover a bug, and high-five type annotations. Here's what I learned. [As it says in the header of this blog, I'm a seasoned Dart developer. However, I certainly don't write Dart every day (I wish!). Don't interpret this post as "Hi, I'm new to Dart". Instead, interpret this post as "I'm applying what I've been documenting."] This post analyzes two versions of the same app, both the original (JavaScript) version and the Dart version. The original version is a proxy for any small JavaScript app, there's nothing particularly special about the original version, which is why it made for a good example. This post discusses the differences between the two implementations: file organization, dependencies and modules, shims, classes, type annotations, event handling, calling multiple methods, asynchronous programming, animation, and interop with JavaScript libraries. F
    Keep reading