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>
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.
Comments