Custom templates in Polymer.js components

Posted: Oct 29, 2016

Polymer.js doesn’t provide a straightforward way to use a custom template in place of the template supplied by a component. Also, HTML code embedded into a component doesn’t have access to properties of the component. Example:

<my-pager>
  <paper-button on-click="firstPage">First</paper-button>

  <template is="dom-repeat" items="[[currentRange]]" as="n">
    <paper-button data-item$="[[n]]">[[n]]</button>
  </template>

  <paper-button on-click="lastPage">First</paper-button>
</my-pager>

Buttons with page numbers won’t be rendered, events fired after clicking on the first button won’t be caught by the my-pager.

In fact, there is a way to make it work by using the Polymer.Templatizer behavior:

<template>
  <content></content>
</template>

<script>
  Polymer({
    is: 'my-pager',

    behaviors: [Polymer.Templatizer],

    // properties and methods

    ready: function() {
      var template = this.queryEffectiveChildren('template');

      this.dataHost = this;

      this.templatize(template);

      this.instance = this.stamp({
        // any properties which you want to pass to the template besides properties of the component
      });

      Polymer.dom(this).appendChild(this.instance.root);
    }
  });
</script>

The HTML provided through the light DOM has to be wrapped into the template tag:

<my-pager>
  <template>
    <paper-button on-click="firstPage">First</paper-button>

    <template is="dom-repeat" items="[[currentRange]]" as="n">
      <paper-button data-item$="[[n]]">[[n]]</button>
    </template>

    <paper-button on-click="lastPage">First</paper-button>
  </template>
</my-pager>

The most interesting line in the code above is one:

this.dataHost = this;

Basically, we share methods and properties of the component with the template we embed through the light DOM. Now, any property and method can be used in the template. Even event listeners catch events fired in the embedded template.

I discovered this option when I was working on upgrading the page-er component to Polymer 1.x. The page-er provides a way to use a custom pagination in place of the default one. The upgrade is finished, if you want to see how the described mechanism work, you can clone my fork and play with it.

Is it a good way to use custom templates?

I guess it isn’t a reliable way. Most likely, the approach will stop working with a new version of the Polymer.js. But, if you understand the risk and you need a workaround to make things work, you can use it. The ideal way will be to get some standard way from the Polymer.js in order to customize HTML of components. Apparently, the Polymer.Templatizer behavior is a step towards that goal.