Friday, February 28, 2014

I Should Really Know By Now When Polymer Data Binding Assigns Values


Tonight, I hope to solve a minor mystery with data binding in the Dart flavor of Polymer. I have a workaround, but the problem surprised me enough that it seems worth investigating.

Things went wonky for me when I tried binding the labels property of the <hello-you> Polymer to the labels attribute of the <polymer-translate> Polymer:
<polymer-element name="hello-you" attributes="locale">
  <template>
    <polymer-translate locale={{locale}} labels="{{labels}}"></polymer-translate>
  </template>
</polymer-element>
The idea of doing this is to provide a vehicle through which the <polymer-translate> Polymer can communicate labels to apply to <hello-you> for the current locale:



And it works. To a point.

What does not work—at least not without a workaround—is watching the labels attribute for changes inside <polymer-translate>:
@CustomTag('polymer-translate-custom')
class PolymerTranslate extends PolymerElement {
  @published Map labels = toObservable({});
  // ...
  ready() {
    super.ready();
    labels.changes.listen((list){
        print('[polymer_translate] $list');
      // Never hit here :(
    });
  }
}
Since <polymer-translate> is the thing changing the labels (e.g. when the locale changes), it might seem a little strange that I want to watch for changes in there as well. In all honesty, my reasons in this case are not as pure as they should be.

It feels like changes to bound variables in Polymer really want to be unidirectional (e.g. <polymer-translate> pushing changes to <hello-you>). Whether that is right is open for debate, but I am already violating this rule by pushing a change in the opposite direction. I am pushing a single attribute change from <hello-you> to <polymer-translate>—a number that will affect a pluralization translation. When that occurs I want <polymer-tranlate> to see the change, and react by updating the other labels attributes accordingly.

But <polymer-translate> never sees the change. Unless…

Unless I wait a single browser event loop before establishing that listener:
@CustomTag('polymer-translate-custom')
class PolymerTranslate extends PolymerElement {
  @published Map labels = toObservable({});
  // ...
  ready() {
    super.ready();
    Timer.run((){
      labels.changes.listen((list) {
        print('[polymer_translate] $list');
        // Now we hit here :)
        update();
      });
    });
  }
  // ...
}
When I observe the same thing in the JavaScript version of this code, it works. Of course, the JavaScript version has observe blocks:
Polymer('polymer-translate-custom', {
  labels: {},
  // ...
  observe: {
    'labels.__count__': 'translate'
  },
  // ...
});
Wait a second… JavaScript. I remember something about object literals and shared state in the JavaScript flavor of Polymer… Dang it. I'm an idiot.

I should expect this kind of behavior when binding variables—in either Dart or JavaScript. When I bind <hello-you>'s locale property to <polymer-translate>'s locale attribute, I am replacing the initial value in <polymer-translate> with a reference to the object in <hello-you>.

When <polymer-translate> is ready(), it still thinks locale is the original value. And then <hello-you> immediately proceeds to replace it with what it thinks locale should be. And I wind up listening for changes on nothing. By waiting for one browser event loop, I give <hello-you> a chance to make that assignment, and thus my code works.

Now that I understand this, I realize that, instead of doing this when <polymer-translate> is ready(), I should do it when <polymer-translate> has enteredView() (or it is attached now?):
@CustomTag('polymer-translate')
class PolymerTranslate extends PolymerElement {
  @published Map labels;
  // ...
  enteredView() {
    super.enteredView();
    labels.changes.listen((list) {
      print('[polymer_translate] $list');
      update();
    });
  }
  // ...
}
It still seems to be called enteredView() in the version (0.9.5) that I have, but I really need to upgrade Dart as well as Polymer. Regardless, this works now. Once <polymer-translate> has entered the view—of <hello-you>—the appropriate labels are set and everything works just fine without the need to wait.

Now that I think about it, this makes complete sense. I have a hard time even recalling why I would have thought otherwise. When I assign an attribute—be it in a template or directly—I replace the original value with the newly assigned value. Not only is the value different, but any associated properties or event listeners are also different.

Sometimes it just helps to take a step back to figure these things out. Other times, it helps to make the mistake in full, public view after struggling with it for a day. Hopefully the latter results in actual learning and remembering!


Day #1,040

Thursday, February 27, 2014

Double Binding Observables in Polymer Dart


Tonight, I hope to apply the lessons learned with my JavaScript approach to internationalization of Polymer back in Dart.

Over the course of the past week or so, this exercise has morphed from an exploration of i18n into an exploration of using strategies in Polymer and, last night, into an exploration on how communication should work between Polymers. Last night's solution eliminates all message passing (in the Smalltalk sense, at least). Instead, I was able to rework my translation strategy such that it relied entirely on bound variables:
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <polymer-translate-custom locale={{locale}} labels="{{labels}}"></polymer-translate-custom>
  </template>
</polymer-element>
Both <hello-you>, which is defined by this template, and the <polymer-translate-custom> Polymer, which is used by <hello-you>, have a locale attribute. The template binds <hello-you>'s locale to <polymer-translate-custom>'s locale attribute. The end result is that when <hello-you> changes its locale, then <polymer-translate-custom> immediately knows about it. And, when <polymer-translate-custom> changes its locale, <hello-you> immediately knows about it. The same goes for labels.

The thing about these two attributes is that they are only changed in one place each. The locale attribute only changes inside <hello-you>, when the user changes the value in the “Language” drop-down list:



Similarly, the labels are only changed inside of <polymer-translate-custom> (when a change in locale is noted).

So it is almost like the bound variables are unidirectional mechanisms for communicating states. Actually, that is exactly what they are in the case. Since this is the first time I have noticed this, I have no idea if this is a useful pattern (i.e. the type that ought to make it into Patterns in Polymer). But the idea is tantalizing. All the more so because it would seem to transcend language and work in Polymer.dart just as easily as in PolymerJS.

To put that theory to the test, I convert the Dart implementation of <hello-you> to use this approach (previously <hello-you> would send <polymer-translate-custom> the translate() message). That goes very smoothly except for two minor things.

First, in the <hello-you> template, I have to use proper Map indexing (with square brackets and strings):
    <-- ... -->
    <p class=help-block>
      {{labels['instructions']}}
    </p>
    <p>
      {{labels['how_many']}}
      <input value="{{count}}">
    </p>
    <p>
      {{labels['count_message']}}
    </p>
    <-- ... -->
Not too horrible in the grand scheme of things, but not quite as nice as JavaScript's dot notation for object literals:
    <!-- ... -->
    <p class=help-block>
      {{labels.instructions}}
    </p>
    <p>
      {{labels.how_many}}
      <input value="{{balloon_count}}">
    </p>
    <p>
      {{labels.count_message}}
    </p>
    <!-- ... -->
The other problem is that I cannot call the translate() method “translate” in <polymer-translate-custom>. Apparently there is a translate attribute. Grr....

Well, since the method is effectively private anyway, I suppose it does not matter too much. So I fall back to the more generic “update”:
@CustomTag('polymer-translate')
class PolymerTranslate extends PolymerElement {
  @published String locale = 'en';
  @published Map labels = {};
  Map translations = {};
  // ...
  update() {
    if (!translations.containsKey(locale)) return;

    var l10n = translations[locale];
    labels['hello'] = l10n['hello'];
    labels['colorize'] = l10n['colorize'];
    labels['instructions'] = l10n['instructions'];
    labels['how_many'] = l10n['how_many'];
    labels['language'] = l10n['language'];
  }
}
Those two issues aside, the conversion goes very smoothly. I also realize the same decrease in the size, the scope, and the complexity of <hello-you> now that it no longer needs to worry about telling <polymer-translate-custom> when to translate—or even be aware of the existence of <polymer-translate-custom> at all.

Except…

I finally realize that I have a tiny problem. The communication is not quite unidirectional. I have been updating the number of balloons—needed for the pluralized message—as “__count__” in the labels. The idea is that the surrounding double underscored indicate that this attribute is exceptional. Unfortunately, this change does not seem to make it to <polymer-translate-custom>. That change registers in <hello-you>:
@CustomTag('hello-you')
class HelloYou extends PolymerElement {
  // ...
  @observable Map labels = toObservable({
    'hello': 'Hello',
    'colorize': 'Colorize'
  });
  // ...
  ready() {
    super.ready();

    changes.listen((list){
      list.
        where((r)=> r.name == #count).
        forEach((_){
          labels['__count__'] = count;
          print(labels); // This runs and shows the updated count
        });
    });
  }
  // ...
}
But the change to labels is not seen in <polymer-translate-custom>:
@CustomTag('polymer-translate-custom')
class PolymerTranslateCustom extends PolymerElement {
  @published Map labels = toObservable({});
  // ...
  ready() {
    super.ready();
    changes.listen((list){
      print(list); // Never hit here...
    });
  }
}
And this has me stumped.

Update: Figure it out. Kind of.

If I add a simple Timer.run() (i.e. defer execution for one event loop), then it works as desired:
@CustomTag('polymer-translate-custom')
class PolymerTranslateCustom extends PolymerElement {
  @published Map labels;
  // ...
  ready() {
    super.ready();
    Timer.run((){
      labels.changes.listen((list) {
        print('[polymer_translate] $list');
        update();
      });
    });
  }
  // ...
}
I believe what is happening here is that, by virtue of the assignment-by-data-binding in <hello-you>'s template, <polymer-translate-custom>'s labels property is replaced completely. By waiting for the event loop, I give that assignment a chance to occur after which I can listen for changes.

I could be wrong about the explanation, but the result is that, with Timer.run() the changes are seen and without, the changes are not seen.


Day #1,039

Wednesday, February 26, 2014

Best Practice for Assigning a Polymer Strategy


Up tonight, I would like to settle on a way to assign the strategy that a Polymer might use to perform some bit of functionality.

Of late, I have been exploring this idea by swapping two internationalization strategies in a simple <hello-you> Polymer:



Switching languages is easy. The locale variable in the <hello-you> template is bound to the select list and the locale attribute of whichever translation strategy is currently being employed:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<link rel="import" href="polymer-translate-custom.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <p>
      {{labels.language}}:
      <select value="{{locale}}">
        <option value="en">English</option>
        <option value="es">Español</option>
        <option value="fr">Français</option>
      </select>
    </p>
    <!-- <polymer-translate locale={{locale}} labels="{{labels}}"></polymer-translate> -->
    <polymer-translate-custom locale={{locale}} labels="{{labels}}"></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
When the locale changes in <hello-you>, the translation strategy immediately knows about it.

What I don't have sussed out is where to assign the translation strategy. In the above, I am doing it in the template—either using the (currently commented out) <polymer-translate> or <polymer-translate-custom>. This has a certain appeal to it—and some implications that I am not sure I fully comprehend.

The appeal is that I am assigning the strategy at the same level as I am importing its code. The implication is that I am effectively importing a library (one or more of the translation libraries). Furthermore, I am instantiating an instance of the imported object inside the template.

In other words, the Polymer template is serving as library glue code and object assignment mechanism. That's a fairly significant shift in thinking—especially in the Dart flavor of Polymer since Dart has proper libraries. But is it appropriate to think of it that way?

The Polymer Elements companion project would seem to have some thoughts on the matter. The <polymer-ajax> element imports the <polymer-xhr> element to serve as strategy for accessing resources with XMLHttpRequest. The <polymer-ajax> element imports the <polymer-xhr> library in the template, but it does not create the <polymer-xhr> instance in the template. Instead it does so in the backing class:
    Polymer('polymer-ajax', {
      // ...
      ready: function() {
        this.xhr = document.createElement('polymer-xhr');
      },
      // ...
    });
I also have to admit that this is more elegant than what I have to do when I want access to the strategy from the backing class. In my case, my i18n strategy contains the string “translate,” so I search all of the children for such an element:
Polymer('hello-you', {
  // ...
  ready: function() {
    var i18n_re = /translate/i;
    for (var i=0; i<this.shadowRoot.children.length; i++) {
      var el = this.shadowRoot.children[i];
      if (i18n_re.test(el.tagName)) this.i18n = el;
    }
  },
  // ...
});
Awful!

So it's an open and shut case, right? I should clean up my code by following the example of the fine Polymer Elements folks.

Or should I?

In assigning the instance in the template, I went out of my way to establish most of the communication between <hello-you> and translation strategy via bound variables and attributes:
    <polymer-translate-custom locale={{locale}} labels="{{labels}}"></polymer-translate>
The only reason that I need to access the translation strategy from the class is because that is currently where the responsibility lies for watching the number-of-balloons <input> field. Once the <hello-you> Polymer sees such a change, it notifies the translation strategy that it needs to translate()—to pick up the latest pluralization translation.

But why not do all communication via bound variables? Why not make a change in state that affects the strategy a simple attribute that can be watched by the strategy? I do just that by syncing the balloon_count variable from the <hello-you> template to a property in the labels that both elements share:
Polymer('hello-you', {
  // ...
  observe: {
    'balloon_count': '_syncBalloonCount'
  },
  _syncBalloonCount: function() {
    this.labels.__count__ = this.balloon_count;
  },
  // ...
});
With that, the translation strategy can now watch for changes to this __count__ variable that it needs to pluralize:
Polymer('polymer-translate-custom', {
  observe: {
    'locale': 'translate',
    'labels.__count__': 'translate'
  },
  // ...
  translate: function() {
    // ...
    var count = this.labels.__count__;
    if (count == "" || count == "0" || count == undefined)
      this.labels.count_message = l10n.balloon_zero;
    else if (count == "1")
      this.labels.count_message = l10n.balloon_one;
    else
      this.labels.count_message = l10n.balloon_plural.replace('__count__', count);
  }
});
I must say that I fancy communicating via shared primitives like this. My <hello-you> backing class is completely unaware of the strategy, save for the need to synchronize values, leaving it to focus on the business of being <hello-you>.

That said, shared state is usually a recipe for disaster. I would feel safer if the primitive could be marked as immutable on whichever side of the communication channel it is appropriate. The effective convention of <hello-you> only changing properties surrounded by double underscores seems a reasonable convention. But is that a long-term recipe for Polymer success?

Regardless, I appreciate this new thought model of Polymer templates as library and instance glue. Even if I wind up sticking with my crazy instance finder or switching to the <polymer-ajax> approach of instantiating the instance in the backing class, I think there is fertile ground to be tilled by limiting communication—and especially method calling—between parent and child Polymers.


Day #1,038

Tuesday, February 25, 2014

Swapping I18n Strategies in Polymer


Thanks to last night's efforts, I believe that I have a much stronger strategy for internationalizing custom Polymer elements. Tonight, I hope to put that to the test by swapping out my current strategy, based on the i18next JavaScript library for a custom written one, similar to the one I used when internationalizing the Dart version.

The existing strategy needs to support two properties and one method. The properties are codified in the Polymer definition as the locale and labels attributes:
<polymer-element name="polymer-translate" attributes="locale labels">
  <script src="polymer_translate.js"></script>
</polymer-element>
The method that my i18n strategy needs to support is, not surprisingly, translate(). This translate() method updates the labels that are shared in common between the element being translated and the translation strategy. The i18next based translate() looks like:
Polymer('polymer-translate', {
  labels: {},
  // ...
  translate: function() {
    this.labels = {
      hello: i18n.translate('app.hello'),
      colorize: i18n.translate('app.colorize'),
      how_many: i18n.translate('app.how_many'),
      instructions: i18n.translate('app.instructions'),
      // ...
    };
  },
  // ...
});
I think the best place to get started in this effort is to comment out the original <polymer-translate> element in the to-be-translated <hello-you> for a new <polymer-translate-custom>:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<link rel="import" href="polymer-translate-custom.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <!-- <polymer-translate locale={{locale}} labels="{{labels}}"></polymer-translate> -->
    <polymer-translate-custom locale={{locale}} labels="{{labels}}"></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
This identifies something of a weakness right away in my approach. The <hello-you> Polymer had been looking for its translation strategy with a simple querySelector('polymer-translate'). That will no longer work now that the strategy could be either <polymer-translate> or <polymer-translate-custom>. For now, I look at all of the Polymer's children for an active “translate” element:
Polymer('hello-you', {
  // ...
  ready: function() {
    var i18n_re = /translate/i;
    for (var i=0; i<this.shadowRoot.children.length; i++) {
      var el = this.shadowRoot.children[i];
      if (i18n_re.test(el.tagName)) this.i18n = el;
    }
  },
  // ...
});
I think I need something more robust than that, but I defer that for another day. For now, I am ready for the custom translation strategy, starting with the template definition:
<link rel="import" href="../bower_components/polymer-ajax/polymer-ajax.html">
<polymer-element name="polymer-translate-custom" attributes="locale labels">
  <template>
    <style>
      :host {
        display: none;
      }
    </style>
  </template>
  <script src="polymer_translate_custom.js"></script>
</polymer-element>
In order to support the same API as the original <polymer-translate>, I am supporting the same attributes: locale and labels. Since I am hand-coding this solution rather than relying on an i18n library, I use <polymer-ajax> from the Polymer Elements project. If this were Dart, I might hand-code the HttpRequest of JSON translation data, but this is JavaScript, so I'll take help in the form of <polymer-ajax>, thank you very much.

As for the backing class to <polymer-translate-custom>, I need to support the translate(), so I start there:
Polymer('polymer-translate-custom', {
  labels: {},
  localizations: {},
  // ...
  translate: function() {
    if (!this.localizations[this.locale]) return;

    var l10n = this.localizations[this.locale];
    this.labels.hello = l10n.hello;
    this.labels.colorize = l10n.colorize;
    this.labels.instructions = l10n.instructions;
    this.labels.how_many = l10n.how_many;
    this.labels.language = l10n.language;

    var count = this.labels.__count__;
    if (count == "" || count == "0" || count == undefined)
      this.labels.count_message = l10n.balloon_zero;
    else if (count == "1")
      this.labels.count_message = l10n.balloon_one;
    else
      this.labels.count_message = l10n.balloon_plural.replace('__count__', count);
  }
});
If there is no localization for the current locale, the initial guard clause exits immediately. Otherwise, I assign the label value from the corresponding localized values. Easy-peasy. Well, easy except for the pluralization of the number-of-balloons label. Since I no longer have a fancy library, I am stuck doing that by hand. Given a translation like:
{
  "hello": "¡Hola!",
  "colorize": "Colorear",
  "how_many": "¿Cuántos?",
  "instructions": "Preséntese para una experiencia personalizada increíble!",
  "language": "Lengua",
  "balloon_zero": "No tengo globos rojos.",
  "balloon_one": "Tengo un globo rojo.",
  "balloon_plural": "Tengo __count__ globos rojos."
}
The pluralization conditional will choose balloon_zero if the current __count__ bound variable/label (see last night) is zero-like. If it is one, then the balloon_one localization is used. Otherwise, the balloon_plural is used, substituting the current balloon count for the __count__ string in the localization file.

That does it for the strategy implementation. I am not quite done, though, as I still need to load the translation files, which I do when the <polymer-translate-custom> element is ready:
Polymer('polymer-translate-custom', {
  // ...
  ready: function() {
    this._loadTranslations();
  },

  _loadTranslations: function() {
    this._loadLocale('en');
    this._loadLocale('fr');
    this._loadLocale('es');
  },
  // ...
});
The _loadLocale() private method is where that <polymer-ajax> Polymer Element comes in handy:
  _loadLocale: function(_l) {
    var that = this;

    var ajax = document.createElement('polymer-ajax');
    ajax.url = '/locales/' + _l + '/translation.json';
    ajax.auto = true;
    ajax.handleAs = "json";
    ajax.addEventListener('polymer-response', function(e) {
      that.localizations[_l] = e.detail.response;
      that.translate();
    });
  },
  // ...
Mercifully, <polymer-ajax> element makes JSON XHRs a breeze—even in JavaScript. I set the URL to point to the same i18n localization files, tell it to parse the response as JSON and then listen for the response to come in. I do not even have to start the request thanks to the auto attribute. When the response comes in, I update the localization for the currently requested locale, then translate.

And it works. I can view a French version of my Polymer:



And a quick update the the Language drop down later, I have the Spanish version:



There are still a few outstanding questions to explore in the next day or two. But this strategy solution to i18n seems like it might be just the ticket for Patterns in Polymer.


Day #1,037

Monday, February 24, 2014

Child Polymers Should Not Access Parent Polymers


I am nearly done with my internationalization strategy for Polymer. But something about my approach is bothering me. And it is really bothering me.

Polymer and the Shadow DOM make it so hard to access the containing element and my current solution is to just have the parent element hand itself over. Specifically, my <hello-you> Polymer is handing a copy of itself to the <polymer-translate> element that it holds in its shadow DOM:
Polymer('hello-you', {
  // ...
  ready: function() {
    this.i18n = this.shadowRoot.querySelector('polymer-translate');
    this.i18n.el = this;
  },
  // ...
});
The advantage of this approach is, of course, that the <polymer-translate> child element can easily update the label field in the <hello-you> parent whenever a change is needed:
Polymer('polymer-translate', {
  // ...
  translate: function() {
    if (this.el === null) return;

    var el = this.el;
    el.hello = i18n.translate('app.hello');
    el.colorize = i18n.translate('app.colorize');
    // ...
  },
  // ...
});
Instead of passing the full object, I think I would like to try binding a variable. I am already binding the locale attribute of <hello-you> to the locale attribute of <polymer-translate>:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <polymer-translate locale={{locale}}></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
So I create the labels binding in the <hello-you> template definition:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <polymer-translate locale={{locale}} labels="{{labels}}"></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
After removing the ready() method that had passed the parent to the child, I modify the child <polymer-translate> template to accept the labels attribute:
<polymer-element name="polymer-translate" attributes="locale labels">
  <script type="text/javascript" src="../bower_components/i18next/i18next.js"></script>
  <script src="polymer_translate.js"></script>
</polymer-element>
Then I modify <polymer-translate>'s translate() method to update the bound labels variable instead of the parent element:
Polymer('polymer-translate', {
  labels: {},
  translate: function() {
    this.labels = {
      hello: i18n.translate('app.hello'),
      colorize: i18n.translate('app.colorize'),
      how_many: i18n.translate('app.how_many'),
      instructions: i18n.translate('app.instructions'),
      language: i18n.translate('app.language')
    };
  },
  // ...
});
With that, I can work back into the parent <hello-you> template to update the various labels. Instead of being direct properties of <hello-you>, the labels are now part of the labels property. So, {{colorize}} becomes {{labels.colorize}}:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <div>
      <h2><span>{{labels.hello}}</span> {{your_name}}</h2>
    </div>
    <p>
      <input value="{{your_name}}">
      <input type=submit value="{{labels.colorize}}!" on-click="{{feelingLucky}}">
    </p>
    <p class=help-block>
      {{labels.instructions}}
    </p>
    <!-- ... -->
    <polymer-translate locale={{locale}} labels="{{labels}}"></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
That actually solves another problem that I had with the original approach—the labels had not been visually distinct from “real” properties. Now it is quite obvious which bound variables are labels and which are direct properties.

With that, I have my translated Polymer working properly again:



This is not a wholesale success however. The second text <input> above previously bound a pluralization message to describe the number of red balloons that the user has. In other words, the <polymer-translate> child element needs access to data from the <hello-you> parent. And I am bit stumped at how best to do this.

For tonight, I bind the input field to a “private looking” property of labels:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <p>
      {{labels.how_many}}
      <input value="{{labels.__count__}}">
    </p>
    <p>
      {{labels.count_message}} <!-- [l10n] pluralization -->
    </p>
    <!-- ... -->
    <polymer-translate locale={{locale}} labels="{{labels}}"></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
Then, in the <polymer-translate> child, I have to do a bit of a dance to ensure that __count__ is not lost when assigning labels:
Polymer('polymer-translate', {
  labels: {},
  translate: function() {
    var count = this.labels.__count__;
    this.labels = {
      // ...
      __count__: count,
      count_message: i18n.translate(
        "balloon",
        { count: count ? parseInt(count, 10) : 0 }
      )
    };
  },
  // ...
});
That could probably be a little cleaner (perhaps updating the existing labels instead of assigning a new object literal each time?). Still, it works. After making that change, I can again greet Fred in French and congratulate him on his 99 ballons rouges:



This could probably use a little more thought, but I feel much better now that I am no longer allowing the child direct access to the parent. It also helps that the labels are visually distinct with this approach. So this seems like a winner.

Day #1,036

Sunday, February 23, 2014

A Dart Strategy for Polymer I18n


If Polymers are to be used across horizontal concerns (sites, apps, pages), then it stands to reason that internationalization is going to be an important use case. I am slowly settling on coming up with a strategy (or should I say Strategy) to accomplish that. Rather that identify a library solution for i18n, I think it makes sense to use a child Polymer that responds to the t() / translate method. I have a working implementation for that in JavaScript. Tonight, I would like to switch back to Dart to see if it will work.

I have every reason to expect that it will work, but that's usually when things go wonky on me…

As with the JavaScript version of my i18n example Polymer, my Dart example application is currently more than just a Polymer. It is a simple <hello-you> Polymer. Also, it is a localized Polymer. As I did with the JavaScript version, I would like to refactor it so that it is a simple <hello-you> Polymer that has a translator associated with it. In other words, I want a translation Strategy.

I begin to realize that the best way to associate other objects in Polymer is to add them to the Polymer definition's <template> instead of as a property of the backing class:
<polymer-element name="hello-you">
  <template>
    <!-- ... -->
    <!-- Lots of bound labels and such to be translated here -->
    <!-- ... -->
    <polymer-translate locale={{locale}}></polymer-translate>
  </template>
  <script type="application/dart" src="hello_you.dart"></script>
</polymer-element>
This allows the containing class to bind its locale variable so that the child object—<polymer-translate> which I will write next—automatically sees that variable change.

Like the JavaScript version, the Dart <polymer-translate> strategy needs to support the locale attribute and a translate method, t(). The HTML definition is UI-less and nothing more than a front for the backing class:
<polymer-element name="polymer-translate">
  <script type="application/dart" src="polymer_translate.dart"></script>
</polymer-element>
The backing class is where the attribute and t() then get defined:
@CustomTag('polymer-translate')
class PolymerTranslate extends PolymerElement {
  @published String locale = 'en';
  PolymerElement target;
  PolymerTranslate.created(): super.created();
  t() {
    // translate the target element here...
  }
}
The implementation details are then left up to the individual strategy. The important part of this approach is that the Polymer being translated needs to bind the locale attribute if it wants to be able to dynamically change translations and it needs to manually invoke the translation Polymer whenever is sees a change that needs a translation. For instance, in my <hello-you> Polymer, when the human user updates the number of balloons currently held, then an update t() translation is needed:
@CustomTag('hello-you')
class HelloYou extends PolymerElement {
  // ...
  @observable int count;
  @observable String count_message;
  // ...
  HelloYou.created(): super.created();

  ready() {
    super.ready();

    i18n = this.shadowRoot.querySelector('polymer-translate');
    i18n.target = this;

    changes.listen((list){
      list.
        where((r) => r.name == #count).
        forEach((_){ i18n.t(); });
    });
  }
  // ...
}
That does the trick. I can set the locale for two separate <hello-you> tags on a page:
      <hello-you locale="fr"></hello-you>
      <hello-you locale="es"></hello-you>
Which results in two dynamic, localized versions of the element:



I rather like this approach, though in Dart it definitely suffers from an inability to work with the built-in dart:intl approach to i18n. That might not be a bad thing considering the effort required for that code generation approach, but it would be nice to be able to support that as well.

An HttpRequest Strategy


For completeness, here is the HttpRequest based strategy for loading and applying localizations:

import 'package:polymer/polymer.dart';
import 'dart:html';
import 'dart:convert';

@CustomTag('polymer-translate')
class PolymerTranslate extends PolymerElement {
  @published String locale = 'en';
  PolymerElement target;
  PolymerTranslate.created(): super.created();

  Map translations = {};

  ready() {
    _loadTranslations();
  }

  _loadTranslations() {
    _loadLocale('en');
    _loadLocale('fr');
    _loadLocale('es');
  }

  _loadLocale(_l) {
    HttpRequest.
      getString('/packages/i18n_example/elements/hello-you-${_l}.json').
      then((res) {
        translations[_l] = JSON.decode(res);
        t();
      });
  }

  attributeChanged(String name, String oldValue, String newValue) {
    if (name == 'locale') t();
  }

  t() {
    if (!translations.containsKey(locale)) return;

    var t = translations[locale];
    target.hello = t['hello'];
    target.colorize = t['colorize'];
    target.instructions = t['instructions'];
    target.how_many = t['how_many'];
    target.language = t['language'];

    var count = 0;
    if (target.count.runtimeType == int) count = target.count;
    if (target.count.runtimeType == String) {
      count = target.count.isEmpty ? 0 : int.parse(target.count);
    }

    if (count == 0) target.count_message = t['balloons_zero'];
    else if (count == 1) target.count_message = t['balloons_one'];
    else target.count_message = t['balloons'].replaceAll('__count__', count.toString());
  }
}



Day #1,035

Saturday, February 22, 2014

Strategy to Internationalize Polymers


I like the i18next JavaScript library for internationalization, but I'm not I like it as the internationalization solution for Polymer. So I begin to wonder if I need to find the solution.

Let's face it, even if I find a great JavaScript solution for i18n and Polymer, I am still out in the cold with Dart. The whole point of Patterns in Polymer is to identify approaches that work in both—to identify solutions that transcend the two languages. So, instead of finding the solution, my current thinking is to identify a solution that covers 80% of the cases, but also makes it easy to swap in a custom solution if Polymer programmers prefer another approach. With that in mind...

Today, I am going to move all of the translation work into a separate object—specifically a separate Polymer. Currently, my <hello-you> Polymer is responsible for updating labels and doing “hello you” kind of work like collection name, number of balloons currently possessed and the preferred language:



The actual locale setting still needs to reside in <hello-you>, but I ought to be able to push everything else down into a custom <polymer-translate> element. Two things need to change in the Polymer definition of <hello-you>—the <script> tag pulling in the i18next library now belongs in the my proposed <polymer-translate> and I need to import the definition of said <polymer-translate>. So this:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <script type="text/javascript" src="../bower_components/i18next/i18next.js"></script>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
Becomes:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
I also need a way to communicate the current locale from the parent <hello-you> down into the <polymer-translate> child. The easiest way of accomplishing this is to add <polymer-translate> as a child of <hello-you>'s template and bind the locale variable of <hello-you> to the locale attribute of polymer-translate:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <polymer-translate locale={{locale}}></polymer-translate>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
With that, any time the user changes the value of locale in <hello-you>, polymer-translate will know about it immediately.

The elided stuff inside of the <hello-you>'s <template> is typical Polymer bound variables and methods:
    <!-- ... -->
    <div id="app">
      <!-- [l10n] hello is a label -->
      <h2><span>{{hello}}</span> {{your_name}}</h2>
    </div>
    <p>
      <input value="{{your_name}}">
      <!-- [l10n] colorize is a label -->
      <input type=submit value="{{colorize}}!" on-click="{{feelingLucky}}">
    </p>
    <!-- ... -->
I note here there this approach does not delineate between locale bound variables and application bound variables—that is they look the same at a glance. The hello and colorize variables are really localized label variables (e.g. Hello, Colorize). The your_name variable is an application variable (the user updates it and the Polymer presents it) and the feelingLucky variable is bound to a method. But the only indication that they serve different purposes are clues from the context in which they are used.

If I could have gotten i18next's jQuery integration working inside of the shadow DOM, I might have used i18next's data attributes. In the absence of that I only note that an improvement is likely needed. Anyhow...

What I need next is for my <polymer-translate> custom element to read the labels from the same i18next source and update its parent element (<hello-you>). To do that, I initialize the i18next library when <polymer-translate> is ready:
Polymer('polymer-translate', {
  ready: function() {
    i18n.init(
      {preload: ['en', 'fr']},
      this.t.bind(this)
    );
  },
  // ...
});
That's just normal i18next initialization—I preload the English and French translations and, once those are loaded, call the t() method to translate the labels in the associated element.

For now, I require the parent Polymer to pass a reference to itself down to this <polymer-translate>:
Polymer('hello-you', {
  // ...
  ready: function() {
    this.i18n = this.shadowRoot.querySelector('polymer-translate');
    this.i18n.el = this;
  },
  // ...
});
Whether <polymer-translate> should directly update properties in the parent is debatable. I use this approach so that <hello-you> need not be responsible for watching for attribute changes. The translate method is then:
Polymer('polymer-translate', {
  observe: { 'locale': '_changeLocale' },
  ready: function() { /* ... */ },
  t: function() {
    if (this.el === null) return;

    var el = this.el;
    el.hello = i18n.t('app.hello');
    el.colorize = i18n.t('app.colorize');
    // ...
    el.count_message = i18n.t(
      "balloon",
      { count: el.count ? parseInt(el.count, 10) : 0 }
    );
  },
  _changeLocale: function() {
    i18n.setLng(this.locale, this.t.bind(this));
  }
});
The main advantage here being that, when a change to the locale is observed, the _changeLocale() method can invoke translate, which immediately updates the labels in <hello-you>.

So, in the end, all of the i18n work is out of my Polymer. Better still, my <polymer-translate> need only support setting the element to be translated and the t() method:
Polymer('hello-you', {
  // ...
  observe: {
    'count': '_updateLabels'
  },
  ready: function() {
    this.i18n = this.shadowRoot.querySelector('polymer-translate');
    this.i18n.el = this;
  },
  _updateLabels: function() {
    this.i18n.t();
  },
  // ...
});
No matter how I refactor or extend <polymer-element>—no matter what strategy I employ to perform translations—my Polymer can remain the same. And yup, it still works switching locales via the dropdown menu:



I still have a few outstanding questions to answer on this approach, but so far this shows promise. Over the next two days I will likely try this approach in Dart and try to swap out the i18n scheme used here in JavaScript. Hopefully both of those efforts will expose any flaws that might exist.


Day #1,034

Friday, February 21, 2014

Switching I18next Locales in Polymer


At this point, I am using a few of the many i18next features in my example <hello-you> Polymer. One that I have yet to put to use is actually switching locales, so that is on tonight's docket.

I fancy the dynamic nature of Polymer a bit too much. Locales are not normally switched on the fly—rather they are determined on the server or at load time—but darn it, it's just too much fun to change one thing and have all of the labels on the screen change.

So I introduce a locale attribute to <hello-you> and bind it in a text field for quick access from the page:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->
    <p>
      <input value="{{locale}}">
    </p>
    <!-- ... -->
    <script type="text/javascript" src="../bower_components/i18next/i18next.js"></script>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
This gives me a locale <input> at the bottom of the Polymer:



I would like to observe the locale bound variable such that it drives the labels to change when the locale changes. After last night (and a bit of refactoring), I have an observer on the count attribute such that, when the user updates the number of balloons, all of the labels are redrawn, including the number of balloons possessed by the Polymer:

Polymer('hello-you', {
  count: 0,
  // ...
  observe: {
    'count': '_updateLabels'
  },
  // ...
  _updateLabels: function() {
    // Simple labels
    this.hello = i18n.t('app.hello');
    this.colorize = i18n.t('app.colorize');
    this.how_many = i18n.t('app.how_many');
    this.instructions = i18n.t('app.instructions');
    // Pluralization message
    this.count_message = i18n.t(
      "balloon",
      { count: this.count ? parseInt(this.count, 10) : 0 }
    );
  },
  // ...
});
The i18next library supports changing the current locale with the setLng() method. So, in addition to observing the count attribute, I observe locale. When locale changes, I invoke setLng() with the new locale. I also supply setLng() with a second argument—a callback to be invoked when the locale is ready:
Polymer('hello-you', {
  count: 0,
  locale: 'en',
  // ...
  observe: {
    'count': '_updateLabels',
    'locale': '_changeLocale'
  },
  // ...
  _changeLocale: function() {
    i18n.setLng(this.locale, this._updateLabels.bind(this));
  },

  _updateLabels: function() {
    // Simple labels
    this.hello = i18n.t('app.hello');
    this.colorize = i18n.t('app.colorize');
    this.how_many = i18n.t('app.how_many');
    this.instructions = i18n.t('app.instructions');
    // Pluralization message
    this.count_message = i18n.t(
      "balloon",
      { count: this.count ? parseInt(this.count, 10) : 0 }
    );
  },
  // ...
});
That callback is just my _updateLabels() method. In other words, when the i18next locale is ready, I update the labels in my Polymer (a bind() is required to keep the current Polymer's context in scope).

And that works! After defining a locales/fr/translation.json:
{
  "app": {
    "hello": "Bonjour",
    "colorize": "Coloriser",
    "instructions": "Présentez-vous une expérience personnalisée incroyable!",
    "how_many": "Combien de ballons?"
  },
  "balloon": "J'ai un ballon rouge.",
  "balloon_plural": "J'ai __count__ ballons rouges."
}
I can dynamically swap the locale by typing my desired locale:



I even fooled Chrome into thinking this was a French page. Nice!

This level of dynamic locale updating will likely never be needed, but it is nice to know that it is possible. I remain somewhat skeptical that i18next is warranted in Polymers. The pluralization is nice, but it seems like something that Polymer could handle without a separate library. Something to think about for tomorrow.


Day #1,033

Thursday, February 20, 2014

I18next, Polymer and Pluralization


Up tonight, I am eager to try some of the i18next internationalization features in Polymer. There are many supported features in i18next, but tonight I am going to stick with pluralization and dates as I've tried them previously with the Dart version of Polymer.

I already have a spot for pluralization in my <hello-you> Polymer, so I start there. From the template, the countMessage bound variable needs to be pluralized:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <p>
      <!-- [l10n] how_many -->
      {{how_many}}
      <input value="{{count}}">
      <!-- [l10n] done -->
      <input type=submit value="{{done}}!" on-click="{{updateCount}}">
    </p>
    <p>
      <!-- updated when updateCount() is invoked -->
      {{count_message}}
    </p>
    <script src="../bower_components/i18next/i18next.js"></script>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
After last night, some of the bound variables in there are already being localized via i18next with simple labels (how_many and done). That results in:



Tonight, I would like to figure out how to move beyond that—to get the updateCount() method to perform some translation.

I start in the translation.json from last night. In there, I add some keys for balloon—I will count the number of red balloons that I have:
{
  "app": {
    "hello": "Hello",
    "done": "Done",
    "how_many": "How many?",
    "instructions": "Introduce yourself for an amazing personalized experience!"
  },
  "balloon": "I have one red balloon.",
  "balloon_plural": "I have __count__ red balloons."
}
The double underscore is how i18next indicates variable interpolation. In this case, if the supplied count is not one (i.e. it is plural), then the number will be interpolated into the second message.

To make that happen from the <hello-you> Polymer, I need the updateCount() method to invoke the appropriate i18next translation:
Polymer('hello-you', {
  // ...
  updateCount: function() {
    this.count_message = i18n.t("balloon", { count: parseInt(this.count, 10) });
  }
});

That works with one red balloon:



Or two red balloons:



Or even 99 red balloons:



After reading the documentation a bit, it seems that i18next defers Dates to other libraries. I cannot say that I blame it since dates in JavaScript are notoriously awful. Still, that is a bit of a letdown keeping me from using this as a one-stop shop for my i18n needs. Even so, the pluralization is definitely nice.



Day #1,032

Wednesday, February 19, 2014

Getting Started with i18next and Polymer


The two chapters that I would like to include in the 1.1 edition of Patters in Polymer are i18n and deployment considerations. I thoroughly enjoyed my recent foray back into the Dart side of things, but I think tonight I need to spend a little time with a JavaScript solution to better understand one of those chapter topics.

So I revisit my old, hand-coded i18n solution by first installing i18next via Bower:
➜  js git:(master) ✗ bower install --save i18next
...
bower i18next#~1.7.2           install i18next#1.7.2

i18next#1.7.2 bower_components/i18next
My current solution has Polymer do the heavy lifting. Specifically, my Polymer reads the specified localization JSON files and replaces values like {{hello}} and {{done}} with the appropriate value from the current locale:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="hello-you-en.json">
<link rel="import" href="hello-you-fr.json">
<link rel="import" href="hello-you-es.json">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <div>
      <h2>{{hello}} {{your_name}}</h2>
    </div>
    <p>
      <input value="{{your_name}}">
      <input type=submit value="{{done}}!" on-click="{{feelingLucky}}">
    </p>
    <!-- ... -->
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
With i18next already installed, I start by adding it to my Polymer with a script tag at the end of the <template>:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="hello-you" attributes="locale">
  <template>
    <!-- ... -->    
    <script type="text/javascript" src="../bower_components/i18next/i18next.js"></script>
  </template>
  <script src="hello_you.js"></script>
</polymer-element>
When I reload the page containing the Polymer, I see that it is now 404ing on /locales/en-US/translation.json, so I add that as:
{
  "app": {
    "hello": "Hello",
    "done": "Done",
    "how_many": "How many?",
    "instructions": "Introduce yourself for an amazing personalized experience!"
  }
}
Then, in my Polymer's ready, I run the i18n initialization:
Polymer('hello-you', {
  // ...
  ready: function() {
    setTimeout(function(){
      i18n.init(function(t) {
        $(".app").i18n();
      });
    }, 500);
    // ...
  }
  // ...
});
Unfortunately, I cannot quite figure out how to make jQuery find the app class in the Polymer's shadow DOM. I am able to configure this by explicitly setting the Polymer bound variables instead:
  ready: function() {
    var that = this;

    setTimeout(function(){
      i18n.init(function(t) {
        $(".app").i18n();
        that.hello = t('app.hello');
        that.done = t('app.done');
        that.how_many = t('app.how_many');
        that.instructions = t('app.instructions');
      });
    }, 500);
    // ...
  }
Which results in an English localized version of the <hello-you> Polymer:



That's really no different from the approach that I already took with raw Polymer except that I was previously able to leverage some of the Polymer platform to avoid the timeout (which prevents the code from running before i18next is loaded). Still, even if I cannot get jQuery working with the shadow DOM, there is still power to be explored in i18next (dates and plural forms). I will pick back up with that tomorrow.

Day #1,031

Tuesday, February 18, 2014

Debugging Dart for Cool People


It's no secret that I am not a fan of IDEs, preferring instead the One True Editor. Having mucked around with the Dart Editor last night, I do envy the debugging ability of the Dart IDE. I have to admit that I have mostly resorted to console printing debugging of late in my Dart code, which is not at all cool. So the question before me is, can I do better debugging without the IDE?

To answer this question thoroughly, I start with a fresh install of Dart. I download archives into ~/Downloads and install things like Dart in ~/local. With that in mind, I grab the latest Dart Editor—I won't use it (much), but bandwidth is cheap and that archive includes the SDK and Dartium in addition to the editor:
$ cd ~/Downloads 
$ wget http://storage.googleapis.com/dart-archive/channels/stable/release/latest/editor/darteditor-linux-x64.zip
$ cd local/
$ rm -rf dart.old
$ mv dart dart.old
$ unzip -dc ~/Downloads/darteditor-linux-x64\ \(5\).zip
Archive:  /home/chris/Downloads/darteditor-linux-x64 (5).zip
   creating: c/dart/
   ...
  inflating: c/dart/editor.properties
  inflating: c/dart/chromium/download_file.dart
  inflating: c/dart/chromium/download_contentshell.sh
  inflating: c/dart/chromium/download_dartium_debug.sh
  inflating: c/dart/DartEditor.ini
I have no idea why “c” is now the top-level directory in the Dart Editor archive. My shell's $PATH expects things in ~/local/dart, so a quick:
$ mv c/dart .
$ rmdir c
And I have the latest version of things ready to roll.

In last night's IDE-generated code, I run pub serve to start the local development HTTP server. Then I fire up ~/local/dart/chromium/chrome. If I were debugging a JavaScript Polymer, I might add a debugger statement to a problem method:
@CustomTag('hello-you')
class HelloYou extends PolymerElement {
  // ...
  feelingLucky() {
    debugger; // THIS WON'T WORK!!!
    var num = new Random().nextInt(colors.length);
    shadowRoot.
      query('h2').
      style.color = colors[num];
  }
}
That does not fly in Dart, however. If I trigger that method, I will get:
Uncaught Error: Class 'HelloYou' has no instance getter 'debugger'.

NoSuchMethodError : method not found: 'debugger'
Receiver: Instance of 'HelloYou'
Arguments: []
This saddens me, if only a little. I realize that the Dart lifestyle is optimized for Dart Editor and, as such, mavericks like myself have to do a little extra work, but still. When I test in Dart, I can mark a single test to run with code (solo_test). It would be nice to do the same when debugging. Since I can't…

I open up the Developer Console and choose the “Sources” tab:



I type the suggested Ctrl+O to open a source file and find hello_you.dart, the backing class behind my <hello-you> Polymer:



In there, I click the line number on which I want to break:



Finally, I trigger the feelingLucky() method in there to find…

Nothing.

The code works just like normal and I am not seeing and debugger / breakpoint kicking in. This is what the dart/chromium/download_dartium_debug.sh script in the Dart Editor archive does. Be warned, it takes a looooong time to do its thing. I run it from the install directory:
$ cd ~/local/dart/chromium 
$ ./download_dartium_debug.sh 
Downloading http://dartlang.org/editor/update/channels/stable/32314/dartium/dartium-linux-x64-debug.zip to dartium-linux-x64-debug.zip.
And then it just sits there. For 10 minutes. My network monitor indicates that I am getting roughly 1 MB/s download speed on this, but it still takes a full 10 minutes before I see:
Download finished.
With that, I have to stop and restart Dartium. Now when I trigger the feelingLucky() method, I get the desired break:



What is nice here is that I am not just using the JavaScript debugger, but a full fledged Dart debugger. It is aware of the variables in my current scope as well as the current call stack:



Just like in the JavaScript debugger, I can click different points in the stack trace to see and interact with the variables that are in scope at those points:



Like any debugger, I can step over, in, and out of the current method. If I step over the random assignment of num, I see the value change in the list of scope variables. Better yet, I can interact with it in the JavaScriptDart Console. In fact, not only can I interact with it, but I can execute arbitrary Dart code here to truly debug my Polymer:



That is awesome. I have editor feature envy no more, because I have the full power of Chrome's debug tool—for Dart.


Day #1,030

Monday, February 17, 2014

Getting Started with Polymer in the Dart Editor


A reader of Patterns in Polymer sent me a question over the weekend asking how to create a simple Polymer.dart application in the Dart Editor. The answer is… I have no idea.

I'm sure the Dart Editor is all kinds of wonderful. Various screencasts and animated GIFs would seem to bear this out. But the fact of the matter is that I have tried on several occasions to use IDEs—going once for as long as 3 months—without success. For better or worse (hint: for better), I am and always will be an Emacs user.

But knowing how to create Polymer applications in the Dart Editor seems like a reasonable thing to know how to do, so…

I start the lovely Editor and select File → New Application. I will call this “hello_you” in an attempt to recreate some of the very simple <hello-you> Polymers that I have previously done in the One True Editor™. I choose the location for the application, leave “Generate sample content” checked and choose “Web application (using the polymer library)” as the content type:



The result is a familiar Polymer application:



I note that the Polymer definition and backing Dart class are both included in the web directory by the generator. I have been placing them in lib/elements when doing this by hand.

I also note that pubspec.yaml for this generated application includes the Polymer transformer:
name: hello_you
description: A sample Polymer application
dependencies:
    polymer: any
transformers:
- polymer:
    entry_points: web/hello_you.html
Without making any changes to the default generated application, I click the run button to start the default application launch:



With that, I am greeted with the sample application running in Dartium:



Interestingly, my reader indicated a problem here. Specifically, right-clicking on the generated HTML would start an empty Dartium. If I do the same with the application HTML, hello_you.html, then it still works. But, if I right-click and run the Polymer HTML (clickcounter.html), then I get a blank Dartium window. So perhaps that is the trouble. Regardless, clicking the Run button avoids this entirely, so that seems the best recommendation.

After that, I create my lib/elements/hello-you.html and backing Dart class and rename web/hello_you.html to my preferred web/index.html:



And, when I click the run button, Dart Editor seems to have figured out that I renamed the web file because now the launched Dartium is pointing to the newly renamed index.html and, more importantly, it is running my simple <hello-you> Polymer instead of the click counter generated Polymer:



So, in the end, I have to admit that it was pretty easy to get both the same Polymer and my custom Polymer up and running in the Dart Editor. Don't get me wrong, I deleted all of the code in the editor at least twice because of dumb (i.e. non-Emacs) key-bindings, but Ctrl-Z reverted the change easily enough. There is no way that anyone is ever going to catch me coding regularly in this thing, but as IDEs go, the Dart Editor seems to have some nice things to offer.


Day #1,029

Sunday, February 16, 2014

Using polymer-ajax to Load Configuration


With the first edition of Patterns in Polymer in the books, it is time to debunk everything. Well, maybe not quite everything, but I ought to keep an open mind on some of the assumptions that I made throughout so that version 1.1 of the book can be that much more solid.

The thing that sticks out the most in my mind as questionable is using <link> imports for configuration files. To be sure, there seem to be some good reasons to use them—in particular they make use of the platform. They also seem to avoid the overhead of dealing with the asynchronous nature of HttpRequest. Using <link> tags is a little messy, however. Deployment utilities do not seem to account for them and extra text content can creep in.

So it mostly works, but I am curious to see how hard HttpRequest configuration might be.

The superficial change will be that the <link> configuration:
      <hello-you>
        <link rel="import" href="hello-you.json">
        <p>And good-bye…</p>
      </hello-you>
Will change to something like:
      <hello-you conf="hello-you.json">
        <p>And good-bye…</p>
      </hello-you>
My main contention with HttpRequest based configuration is that it is a hassle. But this is Polymer, so how much of a hassle is it really? I can include an <polymer-ajax> element from the built-in Polymer elements. If I place it right in the template of my custom <hello-you> tag, I can even bind the conf attribute of <hello-you> to the url attribute of <polymer-ajax>:
<link rel="import" href="../../../packages/polymer_elements/polymer_ajax/polymer_ajax.html">
<polymer-element name="hello-you">
  <template>
    <polymer-ajax url="{{conf}}" handleAs="json"></polymer-ajax>
    <!-- ... -->
  </template>
  <script type="application/dart" src="hello_you.dart"></script>
</polymer-element>
I can also configure <polymer-ajax> to handle that resource as JSON, which I had to perform manually in my <link> approach. To listen and apply this configuration inside the backing class to <hello-you>, it is easiest to grab a reference to <polymer-ajax> and read its response attribute:
@CustomTag('hello-you')
class HelloYou extends PolymerElement {
  // ...
  @published String conf = 'packages/ajax_config/elements/hello-you.json';
  HelloYou.created(): super.created();

  ready() {
    super.ready();
    var ajax = shadowRoot.query('polymer-ajax');
    ajax.
      on['polymer-complete'].
      listen((_) {
        ajax.response.forEach((k, v)=> this[k] = v);
      });
  }
}
The polymer-complete event lets me know that a response has been received from the HttpRequest. I can then read the JSON parsed response directly from the <polymer-ajax> element's response attribute. Since the JSON response is a Map I can iterate over each key-value pair, updating the appropriate value (e.g. greeting, instructions, etc.) in <hello-you>.

And that works. If I use the specialized configuration by explicitly supplying a conf attribute to the <hello-you> Polymer, I get a specialized version of the Polymer:



But, if I remove that attribute and allow the Polymer to load the default configuration, I see:



So in the end, <polymer-ajax> does a pretty decent job of overcoming my objections to HttpRequest messiness. That said, I am not dealing with error conditions, which a <link> approach gives me for free. I am not even attempting to load default configuration and then specialized configuration at the same time here. While not something that <link> gives me for free, worries about load order are eliminated by the platform.

So I think that the <link> approach is still sound. The winning approach is not quite a clear cut as I had thought, however.


Day #1,028