Patrick Hillert
Patrick Hillert

Reputation: 2439

How to not render the content in the <content> tag in Shadow DOM?

I'm currently working on a web component (built with Polymer) to let the consumer of my element put some content into the elements tags like the following:

<my-element mode="fancy">
  <item>First item</item>
  <item>Second item</item>
  <item>Third item</item>
       <!-- ... -->
</my-element>

So the next step is to use <content> inside of my elements definition like shown in the next snippet to project the content into my custom element:

<template>
  <content id="idToHandleIt" select="item"></content>
</template>

The problem here now is, that all items are rendered immediately. But I don't want to show them there, because I have to filter the elements inside of my components (JavaScript) logic for some more criteria other than just the CSS-Selectors that I can use in the select attribute.

Does anybody have a good solution to that problem or is there an API that gives me the possibility to grab the distributed nodes? As I tried for now, the only way to use getDistributedNodes() is if I do the following:

this.querySelector('idToHandleIt').getDistributedNodes();

But I always need that <content> element :(

Upvotes: 0

Views: 269

Answers (2)

Walid Ammar
Walid Ammar

Reputation: 4128

Fortunately you can do that in many ways, but you should probably avoid styling the <content> itself because it's just an insertion point.

However if you want to delay the actual insertion you can set select attribute of <content> to something "isn't valid" something like the following:

<script src="http://www.polymer-project.org/webcomponents.min.js?20141211"></script>
<link rel="import" href="http://www.polymer-project.org/components/polymer/polymer.html">

<polymer-element name="x-item" noscript>
  <template>
    <div>
      <content></content>
    </div>
  </template>
</polymer-element>

<polymer-element name="example-element">
  <template>
    <style>
      .container {
        opacity: 1;
        transition: all 1s linear;
      }
      [unresolved] {
        visibility: none;
        opacity: 0;
      }
    </style>
    <template if="{{counter > 0}}">They will appear after {{counter}}s.</template>
    <div unresolved?="{{counter > 0}}" class="container">
      <content id="idToHandleIt" select="{{counter > 0? 'nope' : 'x-item'}}"></content>
    </div>
  </template>
  <script>
    Polymer({
      counter: 5,
      ready: function() {
        this.countDown();
      },
      countDown: function() {
        if (this.counter <= 0) {
          return;
        }
        this.async(this.countDown, null, 1000);
        this.counter--;
      }
    });
  </script>
</polymer-element>

<example-element>
  <x-item>Item 1</x-item>
  <x-item>Item 2</x-item>
  <x-item>Item 3</x-item>
  <x-item>Item 4</x-item>
  <x-item>Item 5</x-item>
</example-element>

Upvotes: 1

Peter Flannery
Peter Flannery

Reputation: 2101

How about adding to the shadowRoot manually?

<script src="http://www.polymer-project.org/webcomponents.min.js?20141211"></script>
<link rel="import" href="http://www.polymer-project.org/components/polymer/polymer.html">

<polymer-element name="example-element">
  <template></template>
  <script>
    Polymer({

      ready: function() {
        var children = this.children;

        for (var i = 0; i < children.length; i++) {

          var childElement = children[i];

          if (childElement.hasAttribute("banana") && childElement.getAttribute("amount") > 0) {
            
            this.shadowRoot.appendChild(childElement);
            
            // we have to negate one from the index for each append to the shadowRoot
            i--;
            
          }

        }
      }

    });
  </script>
</polymer-element>

<example-element>
  <p banana amount="1">one banana</p>
  <p apple>one apple</p>
  <p banana amount="2">two banana</p>
  <p banana amount="3">three banana</p>
  <p banana amount="0">no banana</p>
</example-element>

Upvotes: 1

Related Questions