Conditionally wrapping <content> insertion points in Polymer

Preston Landers

I am trying to make a Polymer element that is a simple box or container with 3 major elements: a header, body, and footer. The header and footer would be optional, but if they are there, I want to put stuff around them.

My question is how to put a wrapper element around a <content> insertion point that only appears if the select attribute matches something?

My code is something like this (doesn't work):

<polymer-element name="example-card" attributes="">
    <template>
        <paper-shadow z="1">
            <div vertical layout>
                <div class="card card-header" hidden?="{{!$.header}}">
                    <content id="header" select=".header"></content>
                </div>
                <div class="card card-body">
                    <content id="body" select=":not(.footer)"></content>
                </div>
                <div class="card card-footer" hidden?="{{!$.footer}}">
                    <content id="footer" select=".footer"></content>
                </div>
            </div>
        </paper-shadow>
    </template>
    <script>
        Polymer({});
    </script>
</polymer-element>

Expected use - no footer in this example:

<example-card>
    <div class="header">Header...</div>
    <div>Body...</div>
</example-card>

I either want to hide the wrapping div if its content is not selected, or put it in a <template if="..."> to get rid of it from the light DOM altogether. The hidden? expressions above aren't working.

I've tried a few different things with no success, including:

hidden?="{{!$.footer.getDistributedNodes().length}}"

Is there any way to conditionally wrap insertion points depending if their selection matched? Perhaps I am going about this all wrong. Thanks!

EDIT: thanks to Fuzzical Logic's help, this is what my revised version looks like, which uses lodash for collection filtering to only select header and footer classes of immediate children:

<polymer-element name="example-card" attributes="">
    <template>
        <paper-shadow z="1">
            <div vertical layout>
                <template if="{{showheader}}">
                    <div class="card card-header">
                        <content id="header" select=".header"></content>
                    </div>
                </template>
                <div class="card card-body">
                    <content select=":not(.footer)"></content>
                </div>
                <template if="{{showfooter}}">
                    <div class="card card-footer">
                        <content id="footer" select=".footer"></content>
                    </div>
                </template>
            </div>
        </paper-shadow>
    </template>
    <script>
    Polymer({

        domReady: function () {
            // Doesn't work in IE11...
            // this.showheader = this.querySelector(':scope > .header');
            // this.showfooter = this.querySelector(':scope > .footer');

            this.showheader = _.filter(this.children, function(e) { return e.className === "header"; }).length;
            this.showfooter = _.filter(this.children, function(e) { return e.className === "footer"; }).length;
        },
        publish: {
            showheader: {
                value: false,
                reflect: true
            },
            showfooter: {
                value: false,
                reflect: true
            }
        }

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

The problem is not that the hidden? are not working. It's that $.header always resolves to the header with the id === "header" (i.e. this.$.header). This means it will always be truthy. The easiest way to fix this is to set attributes in your domReady event that checks the children.

Polymer('example-card', {

    ... other element code ...

    domReady: function() {
        this.showheader = this.querySelector('.header');
        this.showfooter = this.querySelector('.footer');
    },
    publish: {
        showheader: {
            value: false,
            reflect: true
        },
        showfooter: {
            value: false,
            reflect: true
        }
    },

    ... other element code ...

});

In order to make this work correctly, adjust your element as follows:

<div class="card card-header" hidden?="{{!showheader}}">
    <content id="header" select=".header"></content>
</div>
<div class="card card-footer" hidden?="{{!showfooter}}">
    <content id="footer" select=".footer"></content>
</div>

Important Note

The above domReady code is merely an example and not complete and will find any .header in the tree starting from the content. The correct way to do this would be to check only the children.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Polymer Template: What are valid selects for content insertion points

From Dev

Polymer Check for Insertion Points

From Dev

Assemble: Multiple points of content insertion in layout?

From Dev

Subclass Polymer element filling base class insertion points

From Dev

Conditionally wrapping elements in haml

From Dev

Conditionally add css class in polymer

From Dev

LinearLayout not wrapping content

From Dev

Relativelayout not wrapping its content

From Dev

Wrapping content height on a SnackBar

From Dev

Linear Layout not wrapping content

From Dev

Wrapping only the visible content

From Dev

Gift Wrapping Algorithm with Collinear Points

From Dev

Polymer: Nesting content inside of content

From Dev

Accessing content values in Polymer

From Dev

polymer duplicate element content

From Dev

Observing Content Changes in Polymer

From Dev

Conditionally adding a CSS class to an element with Polymer

From Dev

bootstrap responsive table content wrapping

From Dev

wrapping child node content in xquery

From Dev

floating ajax content not wrapping as wanted

From Dev

wrapping Wordpress text content in div

From Dev

Wrapping Wordpress text content in .class

From Dev

MVVMCross - MvxGridView is not wrapping the content height

From Dev

Bind data to content element in Polymer

From Dev

Polymer input label using content

From Dev

AngularJS Show Content Conditionally By Expression

From Dev

Wrapping validation errors for polymer-element paper-input

From Dev

Polymer 1.x: Wrapping a jQuery range slider inside a Polymer element

From Dev

wrapping some content except the first element