montrealist
montrealist

Reputation: 5693

nesting elements and dynamic content inside dom-repeat - Polymer 1.0

I have a <parent> element, a <tabs> element inside it with an arbitrary number of tabs (purely for hiding/showing logic in the UI), and a <child> element inside each <tab>. Right now I have the following working:

<!-- inside parent.html: -->
<tabs></tabs>

<!-- inside tabs.html: -->
<template is="dom-repeat" items="{{tabs}}" as="tab" index-as="item_no">
    <section>
        <child id="element-{{tab.index}}"></child>
    </section>
</template>

Only <parent> knows how many instances of <child> there needs to be (<tabs> merely receives an array from <parent> and iterates over it.

Is there a way to not hard-code <child> inside the local DOM of <tabs>? Thinking of using <content> and light DOM but no idea where to even start. Would it be a promising route to take?

Desired state:

<!-- inside parent.html: -->
<tabs>
    // somehow specify base content to be rendered in each tab
</tabs>

<!-- inside tabs.html: -->
<template is="dom-repeat" items="{{tabs}}" as="tab" index-as="item_no">
    <section>
        // somehow inject stuff from parent element, perhaps via <content>?
    </section>
</template>

Upvotes: 2

Views: 699

Answers (1)

alesc
alesc

Reputation: 2780

This is my interpretation of your question, so I am not really sure if it will be OK with you. If I misunderstood you, please drop a comment and I will gladly update my answer.

I have come up with a simple element composition, requiring no dom-repeat or manual template stamping. The solution consists of two custom elements, namely my-parent and my-child.

The definitions for both custom elements are the following:

<dom-module id="my-parent">
  <template>
    <tabs>
      <content></content>
    </tabs>
  </template>
  <script>
    Polymer({
      is: 'my-parent',
    });
  </script>
</dom-module>

<dom-module id="my-child">
  <template>
    <section>
      <content></content>
    </section>
  </template>
  <script>
    Polymer({
      is: 'my-child',
    });
  </script>
</dom-module>

And the proposed usage of them is the following:

<my-parent>
  <my-child>First tab</my-child>
  <my-child>Second tab</my-child>
  <my-child>Third tab</my-child>
</my-parent>

Online demo: http://jsbin.com/hibuzafapu/1/edit?html,output

The resulting computed HTML code looks something like this:

<my-parent>
  <tabs>
    <my-child>
      <section>
        First tab
      </section>
    </my-child>
    <my-child>
      <section>
        Second tab
      </section>
    </my-child>
    <my-child>
      <section>
        Third tab
      </section>
    </my-child>
  </tabs>
</my-parent>

If I understood you correctly, then only the <my-child> tag wrapping the <section> tag is redundant. Currently the aforementioned tag does nothing and is just a block-level element that wraps everything (just like a div). If this bothers you, then you can actually omit the <section> tag and put all the styling directly on the <my-child> tag.

In this case, the resulting computed HTML would look something like this:

<my-parent>
  <tabs>
    <my-child>
      First tab
    </my-child>
    <my-child>
      Second tab
    </my-child>
    <my-child>
      Third tab
    </my-child>
  </tabs>
</my-parent>

UPDATE

In order to add some dynamics to the solution (adding/removing tabs), you have two options: use dom-repeat and stamp the items in light DOM, or push the items array into the my-parent element and use dom-repeat there. Both options are very similar to implement and don't have much difference in the way they work.

Option A: stamping in light DOM:

Definitions for both custom elements remain unchanged, the only difference is how you use them. Instead of hardcoding the light DOM, you make it more dynamic.

<dom-module is="tmp-element">
  <template>
    <my-parent>
      <template is="dom-repeat" items="[[myItems]]">
        <my-child>[[item.content]]</my-child>
      </template>
    </my-parent>
  </template>
  <script>
    Polymer({
      is: 'tmp-element',
      ready: function() {
        this.myItems = [
          { content: "First tab" },
          { content: "Second tab" },
          { content: "Third tab" },
        ],
      };
    });
  </script>
</dom-module>

<tmp-element></tmp-element>

The tmp-element is used purely to create a binding scope and to feed the data into the dom-repeat.

Live demo: http://jsbin.com/gafisuwege/1/edit?html,console,outputenter link description here

Option B: stamping inside parent:

In this option, the parent needs to have an additional property, in which will we will supply the array of items.

The new version of the my-parent element is the following:

<dom-module id="my-parent">
  <template>
    <tabs>
      <template is="dom-repeat" items="[[items]]">
        <my-child>[[item.content]]</my-child>
      </template>
    </tabs>
  </template>
  <script>
    Polymer({
      is: 'my-parent',
      properties: {
        items: Array,
      },
    });
  </script>
</dom-module>

And the usage is:

<dom-module is="tmp-element">
  <template>
    <my-parent items="[[myItems]]"></my-parent>
  </template>
  <script>
    Polymer({
      is: 'tmp-element',
      ready: function() {
        this.myItems = [
          { content: "First tab" },
          { content: "Second tab" },
          { content: "Third tab" },
        ];
      },
    });
  </script>
</dom-module>

<tmp-element></tmp-element>

Here, I have also used a tmp-element (a different one than before) to feed the my-parent its' data.

Live demo: http://jsbin.com/kiwidaqeki/1/edit?html,console,output

Upvotes: 1

Related Questions