Chris Dion
Chris Dion

Reputation: 33

Polymer custom element with template-as-content

In the code below, the content "Foo" of template#bar are always empty when I try to access it programatically or when inspecting the DOM in Chrome. Can someone explain why?

In general, how does one provide a template defined in an outer element to an inner element so the inner element can access the content and conditionally clone or import that content?

I am using polymer 0.4.2.

<polymer-element name="x-inner" noscript>
    <!--
        How can I access the content "Foo" of <template>Foo</template>,
        So that I can import/clone it here?

        Using <content> moves the template from x-outer to x-inner,
        but the template's .content property is empty, instead of 'Foo' as I expected.
     -->
    <content></content>
</polymer-element>

<polymer-element name="x-outer" noscript>
    <template>
        <x-inner>
            <!--
                How can I pass a template to a custom element?
                I don't want the contents of this template to be rendered
                here in x-outer, but instead conditionally rendered by x-inner
             -->
            <template id="bar">Foo</template>
        </x-inner>
    </template>
</polymer-element>

<x-outer></x-outer>

Upvotes: 3

Views: 1283

Answers (1)

Scott Miles
Scott Miles

Reputation: 11027

This topic is potentially complicated, below is something to get you started.

(This is the third update to this answer, confirming the bit above about 'complicated' =P).

Polymer includes the TemplateBinding.js library.

The TemplateBinding.jslibrary imbues <template> with numerous features, including data-binding to models, conditional stamping, and replication/iteration via arrays. It also adds a feature whereby cloned nested templates do not replicate their own contents, preventing a possible explosion of useless nodes when iterating. Instead, TemplateBinding.js creates references in cloned-nested-templates to original content-ful templates. The upshot is that if you are using TemplateBinding.js you should use template.createInstance() API for best results.

Now, when using raw templates without TemplateBinding.js, you can stamp a template simply using var nodes = document.importNode(template.content, true). Of course, in this case you do not get the nested template replication optimization (which may or may not matter).

Note:

  1. I removed the <content> node from the <x-inner> template because it serves no purpose. The code below plucks the template directly out of light-dom, and stamps the instance into the shadow-root.
  2. Declare x-inner before x-outer because the latter depends on the former.

Example code:

<x-outer></x-outer>

<polymer-element name="x-inner">
<template>
</template>
<script>

  Polymer({
    domReady: function() {
      this.renderTemplate();
    },
    renderTemplate: function() {

      // note: this only works if `template` is a true child of `this`
      // (as opposed to projected) 
      var template = this.querySelector('template');

      // use createInstance from TemplateBinding.js library API
      this.shadowRoot.appendChild(template.createInstance());

      /* 
      // this would work for raw templates, but Polymer includes TemplateBinding.js
      this.shadowRoot.appendChild(stampTemplate(template));
      */

      /* 
      // if you don't know whether TemplateBinding.js exists or not,
      // you could do something like this (see stampTemplate definition below)
      this.shadowRoot.appendChild(stampTemplate(template));
      */

      /*
      // this way uses the binding feature of TemplateBinding.js
      template.setAttribute('bind', '');
      template.model = { /* some data */ };
      */
    }
  });

  // use best available API
  function stampTemplate(template) {
    if (template.createInstance) {
      return template.createInstance();
    } else {
      return document.importNode(template.content, true);
    }
  }

</script>
</polymer-element>

<polymer-element name="x-outer" noscript>
<template>

  <x-inner>
    <template id="bar">Foo</template>
  </x-inner>

</template>
</polymer-element>

http://jsbin.com/nemaha/14/edit

Upvotes: 1

Related Questions