Sunday, March 2, 2014

The Precipication Pattern and Polymer


Tonight, I try my hand at sending messages from parent to child Polymers.

I am still unsure if this is necessary in Polymer—communicating state through bound variables seems to work nicely. But I still tend to think it may come in handy.

The process has a similar feel to communicating between objects in Backbone.js. My Recipes with Backbone co-author, Nick Gauthier, came up with a really nice mental model for how this ought to work in Backbone that still helps me to this day. In it, messages could be sent from high order objects to lower, but lower order objects were only allowed to generate events back to higher order objects. That is, messages could precipitate down (the router could invoke a view method, a collection could call a model method), but information from the lower order objects are only allowed to evaporate back up in the form of events.

(Shameless plug: Nick contributed a wonderful chapter on this in Recipes with Backbone — you should buy it!)

It is completely possible that I am conflating ideas from one paradigm into another inappropriately. But there are certain aspects of Polymer that strongly suggest a similar approach would work here. Polymer does not have the built-in hierarchy of object types that Backbone has, but there are still parent Polymers that contain child Polymers. The shadow DOM makes it very difficult for a child element to access the parent Polymer, which seems very much like a built-in enforcement preventing lower order objects from accessing higher order objects. While child objects cannot easily access parent Polymers, they can very easily fire custom events for the parents to consume.

Plus, it is easy for the parent to access child Polymers, which is where I start tonight. I have developed a slight preference for defining child elements inside the template of a Polymer. For my <hello-you> sample Polymer, I have been creating an instance of the child <polymer-translate> to localize labels:
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you">
  <template>
    <!-- hello-you definition here... --->
    <polymer-translate locale={{locale}} labels={{labels}}></polymer-translate>
  </template>
  <script type="application/dart" src="hello_you.dart"></script>
</polymer-element>
I could create an instance of the Polymer in the backing class and add it to the shadow DOM, but, as I mentioned, I have developed a (potentially irrational) attachment to “instantiating” child Polymers in the same place that I “import” the library (with the <link> tag at the top). I also like seeing the bound variables front and center like that.

I still need a way to access that instance from inside the backing class if I am to send messages from the backing class to the child. I had previously lamented the inability to easily access the instance of a child Polymer, but I believe that Polymer has me covered here. If I add an ID attribute to the element in the template:
<link rel="import" href="polymer-translate.html">
<polymer-element name="hello-you">
  <template>
    <!-- hello-you definition here... --->
    <polymer-translate id="l10n"
                       locale={{locale}}
                       labels={{labels}}></polymer-translate>
  </template>
  <script type="application/dart" src="hello_you.dart"></script>
</polymer-element>
Then I can use Polymer's built-in automatic node finding feature to grab the element from the dollar-sign Map:
@CustomTag('hello-you')
class HelloYou extends PolymerElement {
  // ...
  HelloYou.created(): super.created() {
    new Timer(
      new Duration(seconds: 8),
      () {
        $['l10n']
          ..locale = 'es'
          ..update();
      }
    );
  }
  // ...
}
Then I can send any number of messages to the child element. In this case, after updating its locale property, I send the update message down to the <polymer-translate> instance that I have named l10n.

With that, I am precipitating the update message down to all instances of <polymer-translate> so that they can update themselves in Spanish (because we can all use a little more Spanish in our lives):



That really seems to work very well. If the child Polymer needed to communicate up, the messages could quite easily “evaporate” as events.

As I said from the outset, I could very well be seeing parallels where they do not exist. I could also be identifying a solution in need of a problem—variable binding really does work quite well. But, this feels right. I am not sure that I will include it directly in Patterns in Polymer just yet, but I will not hesitate to rely on it if the need arises.


Day #1,042

1 comment:

  1. Hi Chris,

    I am currently looking at this problem of parent elements communicating with children.
    The issue I am facing is when I have multiple depth children, therefor in every created or similar I would need to pass a reference to the parent or the event etc downwards for the next child to handle or/and pass onwards.
    Was wondering if you had thought about this at all?
    Have been thinking I might be able to use the Polymer-Signals element.
    Do you have any thoughts on this?

    Cheers Shaun

    ReplyDelete