Tuesday, June 3, 2014

Polymer.dart: Best in JavaScript?


Bleh. That seems to sum up the current state of <core-*> elements in Polymer.dart.

In addition to maintaining the usual pubspec.yaml dependency file for the Dart Pub packager, I also have to pull down the JavaScript version of the <core-*> custom element (like <core-ajax>). I also have to manually edit the core-*> elements to use the same polymer.html source file as the Dart custom element. And it still doesn't work.

The problem that I currently face is getting callback events to pass useful data into my Dart code. The Polymer definition includes a series of <core-ajax> elements that each invoke the element's responseReceived() method when the Ajax request finishes successfully:
<link rel="import"
      href="bower_components/core-ajax/core-ajax.html">
<polymer-element name="x-pizza">
  <template>
    <core-ajax
       auto
       id="pizza.svg"
       url="/packages/svg_example/images/pizza.svg"
       on-core-response="{{responseReceived}}"></core-ajax>
    <!-- ... -->
  </template>
  <script type="application/dart" src="x_pizza.dart"></script>
</polymer-element>
The idea here is simple enough: I want my custom element to load several SVG assets to be used when building pizzas in the custom <x-pizza> element:



There might be better ways to accomplish this, but this seemed the best option given the vagaries of SVG. Regardless of the best option, using <core-ajax> like this should work. That is the entire point of having a set of core-* elements. But it does not work. The responseReceived() is invoked, but the event details and the details parameters supplied are always null:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  responseReceived(e, detail, node){
    svgContent[node.id] = detail['response'];
    if (svgContent.length == shadowRoot.queryAll('core-ajax').length) {
      svgLoaded.complete();
    }
    if (node.id == 'pizza.svg') _updateGraphic();
  }
  // ...
}
That is where I left off yesterday because nothing I could do would convince <core-ajax> to send useful information into the callback method in Dart. In the fresh light of day, however, I have the sneaking suspicion that this is going to work when compiled into JavaScript—I had tested only in Dartium, not a standard browser.

So I load the element up in Chrome, for which the pub serve testing web server is happy to compile, and find:



It works perfectly. And this makes me so mad.

I suspected this “fix” would work because I have seen this before in Polymer.dart. Strange things fail in the Dart VM, but work just fine when compiled to JavaScript. This is more than a bit of an annoyance. I would much rather smoke test in Dart than compiled JavaScript—it is faster in Dart and the error messages are more useful. For now, I will trust in the Polymer.dart folks to fix this when they get the core-* elements into a Dart package.

For what it's worth, I was able to get this working in the Dart VM by reading the response property directly from the <core-ajax> element, BUT I had to wait roughly 100 milliseconds before trying to do so:
  responseReceived(e, detail, node){
    new Timer(new Duration(milliseconds: 100), (){
      svgContent[node.id] = node.attributes['response'];
      if (svgContent.length == shadowRoot.queryAll('core-ajax').length) {
        svgLoaded.complete();
      }
      if (node.id == 'pizza.svg') _updateGraphic();
    });
  }
Obviously that is nowhere near an ideal solution. But it's something—at least until the Polymer.dart team does ship a package of the core- elements for Dart developers.


Day #83

7 comments:

  1. And I wish they would hurry up and release the Dart sanitised versions for us.

    I have written some Python scripts to help sanitise the Polymer JS Elements for Polymer Dart consumption, since I don't want to do it manually everytime I do an update with bower. Times like these I am tempted to go completely JavaScript for Polymer projects. I'm sure they don't have the problems we have with Dart. I'm not that tempted though.

    ReplyDelete
  2. Have you seen this? https://github.com/Polymer/designer It's JS elements only, but still quiet cool to see what you can do, visually, just Polymer Components.

    ReplyDelete
    Replies
    1. I haven't hard a chance to play with it yet, but it looks pretty cool :)

      Delete
    2. Quick tip, use the drag-drop branch, it has a draggable list of components on the left hand side, which is missing from the other two branches

      Delete
  3. Polymer Designer is the future of web development. Watch this video: https://www.youtube.com/watch?v=djQh8XKRzRg
    The real question is: will the future web be built with Javascript polymers or Dart polymers?

    ReplyDelete
  4. Quick question. I understand compiling to JS, but do you need to use bower to load a library of core-* elements? Or because the core-* elements are included in the JS version of polymer you get access to the elements when it compiles to JS and uses the JS version of polymer (basically you just have to load the polymer library in Dart to get core elements in JS)?

    ReplyDelete
  5. FYI, I encountered the same issue (detail being null) with polymer 0.10.0-pre7, but I was able to get the value thanks to jsinterop. It's not the most straightforward way of retrieving and assigning a value, but it works:

    querySelector("core-ajax").addEventListener("core-response", (e) {
    var jsResponse = new JsObject.fromBrowserObject(e)['detail']['response'];
    new JsObject.fromBrowserObject(querySelector('#foo'))['model']['response'] = jsResponse;
    }

    I just updated to 0.10.0, and after the tweaks to reintroduce a main function, removing ";component=1" and the init decorator, it's working as well there.

    For reference, I asked about it on https://groups.google.com/a/dartlang.org/d/msg/web/NN2CumFaQ8k/MfgYzjiuu_MJ and you have the explanation why it's not working on dartium, but it does work once compiled to javascript :)

    ReplyDelete