Tuesday, April 8, 2014

Still Almost: JS Interop in Polymer.dart


Up today, I try to finish my efforts to get JavaScript Polymer elements working inside Polymer.dart elements.

As noted last night, the 0.10 release of Polymer.dart, which currently only works with the dev channel / 1.3 version of Dart, promises to make this possible. After last night, I actually seem to have this nearly working. Of course “nearly working” is another way of saying not working at all, so let's see if I can address that.

I continue to work with my <x-pizza> pizza builder element that will star in several Patterns in Polymer chapters. This element makes use of a second element under the covers—<x-pizza-toppings>—to enable a hungry pizza buyer to customize his/her pizza:



Since Patterns in Polymer comes in two flavors (Dart and JavaScript), I have two different flavors of both <x-pizza> and x-pizza-toppings>. To experiment with JavaScript interoperability from Dart Polymer elements, I am trying to use the JavaScript version of <x-pizza-toppings> from the Dart version of <x-pizza>.

The last error that I saw last night turns out to be fairly easy to solve. To access those “model” properties from my JavaScript element, I need to use dart:js to grab a Dart proxy to a browser object:
updatePizzaState([_]) {
    pizzaState = JSON.encode({
      'firstHalfToppings': new JsObject.fromBrowserObject($['firstHalfToppings'])['model'],
      'secondHalfToppings': new JsObject.fromBrowserObject($['secondHalfToppings'])['model'],
      'wholeToppings': new JsObject.fromBrowserObject($['wholeToppings'])['model']
    });
  }


Without the JsObject.fromBrowserObject wrapper, I would get invalid property errors when trying to access the “model” property of these child-JavaScript objects.

That leaves me with another error that is not nearly as obvious:
Uncaught TypeError: undefined is not a function polymer-expressions.js:552
(anonymous function) polymer-expressions.js:552
Through trial an error (the Dartium debugger still leaves much to be desired), I eventually track it down to a fairly innocuous on-click bound method in the JavaScript <x-pizza-toppings> element:
<polymer-element name="x-pizza-toppings" attributes="ingredients name">
  <template>
    <!-- ... -->
    <p>
      <button id="add" on-click="{{add}}" type="button" class="btn btn-default">
        Add {{name}}
      </button>
    </p>
  </template>
  <script>Polymer('x-pizza-toppings', {
  // ...
  add: function() {
    this.model.push(this.current);
    this.current = '';
  },
  // ...
});
</script>
</polymer-element>
When the pizza buyer clicks the Add button, whatever current ingredient is selected is then added to the internal model. Only it isn't. At least not when used in Polymer.dart. I am unable to solve this tonight, but I do determine that, if I build this in a JavaScript element (instead accessing it in Dartium), I am able to click the button to access the add() method. So it would seem that something is missing from the Dart implementation.

Bummer. This has the feel of a rabbit hole I would rather not travel down at this time, but I will sleep on it to see if I can come up with a better way to investigate. If not, there is still one thing that I do not have working in the compiled-to-JavaScript version of the Dart+JavaScript interop experiment: my ingredients list, which comes from <x-pizza> is not being bound properly inside <x-pizza-toppings>. Hopefully I can solve that mystery tomorrow.


Day #28

No comments:

Post a Comment