I have a problem with using iron-collapse. When i use it throws a error to console. I have no idea.
Here is my example of template structure:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-collapse/iron-collapse.html">
<dom-module id="page-faq">
<template>
<header-layout id="header"></header-layout>
<bread-crumb id="bread-crumb"></bread-crumb>
<div class="wrapper">
<div id="faq-container">
<div id="tabs">
</div>
<template is="dom-repeat" items="[[items]]">
<div class="collapse-container">
<button on-click="toggle">[[item.content.title]]</button>
<iron-collapse id="collapse">
<div class="collapse-content">
[[item.answer]]
</div>
</iron-collapse>
</div>
</template>
</div>
</div>
<footer-layout id="footer"></footer-layout>
</template>
<script type="text/javascript">
class PageFaq extends Polymer.Element {
static get is() {
return 'page-faq'
}
toggle() {
this.$.collapse.toggle();
this.$.button.setAttribute('aria-expanded', this.$.collapse.opened);
};
}
customElements.define(PageFaq.is, PageFaq);
</script>
</dom-module>
And when i click button it gives me
TypeError: Cannot read property 'toggle' of undefined
What did i do wrong ? Any advice ?
What you're doing is the hard way, but I don't blame you because the documentation is misguiding. There is one easier way – and more following the Polymer thinking – to control iron-collapse, and that's with a variable. I named it ironCollapsableOpened in this case.
<button on-click="toggle">[[item.content.title]]</button>
<iron-collapse opened="[[ironCollapseOpened]]">
<div class="collapse-content">
[[item.answer]]
</div>
</iron-collapse>
toggle() {
this.set('ironCollapseOpened', !this.ironCollapseOpened);
};
iron-collapse creates a collapsible block of content. By default, the
content will be collapsed. Use opened or toggle() to show/hide the
content.
https://www.webcomponents.org/element/PolymerElements/iron-collapse
Related
I am trying to download div content of custom element using document.getElementById of the div and trying to implement download option from the JS FIddle - http://jsfiddle.net/evx9stLb/
From console, I am getting below error
pen.js:6 Uncaught TypeError: Cannot read property 'innerHTML' of null
at download (pen.js:6)
at HTMLButtonElement.onclick (index.html:15)
HTML:
<head>
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-collapse/iron-collapse.html">
</head>
<body>
<x-foo></x-foo>
<button onClick="download()">Download</button>
<dom-module id="x-foo">
<template>
<button on-click="toggle">toggle collapse</button>
<div id="content">
<iron-collapse id="collapse">
<div>Content goes here...</div>
</iron-collapse>
</div>
</template>
</dom-module>
</body>
JS:
function download(){
var a = document.body.appendChild(
document.createElement("a")
);
a.download = "export.html";
a.href = "data:text/html," + document.getElementById("content").innerHTML;
a.click();
}
class XFoo extends Polymer.Element {
static get is() { return 'x-foo'; }
static get properties() {
return {};
}
toggle() {
this.$.collapse.toggle();
}
}
customElements.define(XFoo.is, XFoo);
Code which I am below - https://codepen.io/nagasai/pen/ZyRKxj
Make some updates, and help this would help,
HTML
<head>
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-collapse/iron-collapse.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<button on-click="download">Download</button>
<button on-click="toggle">toggle collapse</button>
<div id="content">
<iron-collapse id="collapse">
<div>Content goes here...</div>
</iron-collapse>
</div>
</template>
</dom-module>
</body>
JS
class XFoo extends Polymer.Element {
static get is() { return 'x-foo'; }
static get properties() {
return {};
}
toggle() {
this.$.collapse.toggle();
}
download(){
var a = document.body.appendChild(
document.createElement("a")
);
a.download = "export.html";
a.href = "data:text/html," + this.$.content.innerHTML;
a.click();
console.log(this.$.content.innerHTML);
}
}
customElements.define(XFoo.is, XFoo);
https://codepen.io/renfeng/pen/BZOQro
a document query (on light dom) won't pierce the shadowDom. To do that you have to specifically select the element and query it's shadowRoot.
it would look something like this
a.href = "data:text/html," + document.getElementsByTagName('x-foo')[0].shadowRoot.querySelector('#content').innerHTML;
BUT only do this if you can't modify the element itself. It's not nice to stir around in someone else's shadowRoot.
As shown by Frank R. its far better to modify the element itself and provide a download functionality.
You can trigger this easily from an external element with something like
document.getElementsByTagName('x-foo')[0].download();
DOM under the shadow Root, or the shadow DOM, can not be accessed via innerHTML. It is not supposed to be. Just the way it is.
So, No, you simply can not get the shadow DOM contents via innerHTML.
There used to be access now deprecated to shadowDOM via vanilla javascript earlier
and also discussed here
However, with shadow DOM V1 beig the norm now, you may have to just wait and watch if you can pierce the shadowDOM
An alternative would be, to move your entire DOM in the custom element, outside of it, Using Slots.
Slots distribute content, so, the page that uses your element, can access it via innerHTML.
You could possibly try hacky ways like the one mentioned here
I need to include a vaadin-grid in a custom Polymer 2 element and need to handle the row selection event, but I can't seem to get it to work. I've managed to cobble together this from the various starter templates and demos on offer, and the basic click event handler works, but I have no idea how to handle the row selection. I'm actually using v3.0.0-beta1 of the vaadin-grid because I couldn't get v2 to work, but I don't think that's my problem.
Does anyone know how to handle events in vaadin components when you include them in your own custom elements?
Thanks.
<link rel="import" href="bower_components/polymer/polymer-element.html">
<link rel="import" href="bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="bower_components/vaadin-grid/vaadin-grid.html">
<dom-module id="my-element">
<template>
<style>
:host {
display: block;
}
</style>
<iron-ajax auto url="https://demo.vaadin.com/demo-data/1.0/people?count=200" handle-as="json" last-response="{{users}}"></iron-ajax>
<vaadin-grid aria-label="My Test Grid" items="[[users.result]]" id="grid">
<vaadin-grid-column width="50px" flex-grow="0">
<template class="header">#</template>
<template>[[index]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">First Name</template>
<template>[[item.firstName]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">Last Name</template>
<template>[[item.lastName]]</template>
</vaadin-grid-column>
<vaadin-grid-column width="150px">
<template class="header">Address</template>
<template>
<p style="white-space: normal">[[item.address.street]], [[item.address.city]]</p>
</template>
</vaadin-grid-column>
</vaadin-grid>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
ready() {
super.ready();
this.$.grid.addEventListener('click', e => {
this._handleClick(e)
});
// I added this listener code from here: https://vaadin.com/elements/-/element/vaadin-grid#demos
// but it does nothing. I've also tried adding it to this, this.$, this.$.grid without success.
// Should this event listener be added here, or if not, where exactly? The docs are very unclear.
addEventListener('WebComponentsReady', function() {
Polymer({
is: 'my-element',
properties: {
activeItem: {
observer: '_activeItemChanged'
}
},
_activeItemChanged: function(item) {
this.$.grid.selectedItems = item ? [item] : [];
console.info('row clicked');
}
});
// this works and outputs info like this: "vaadin-grid-cell-content-17 was clicked."
_handleClick(e) {
console.info(e.target.id + ' was clicked.');
}
}
window.customElements.define(MyElement.is, MyElement);
</script>
</dom-module>
I think that my code in the addEventListener is Polymer 1.x syntax but I'm not sure how to achieve the same result using Polymer 2.x.
I used only vaadin-grid v2, but I downloaded the v3.0.0-beta1 and took a look inside the package, at demo/row-details.html
There is an example on how to handle the active row change event.
<vaadin-grid on-active-item-changed="_onActiveItemChanged" id="grid" aria-label="Expanded Items Example" data-provider="[[dataProvider]]" size="200">
<template class="row-details">
<div class="details">
<img src="[[item.picture.large]]"></img>
<p>Hi! My name is [[item.name.first]]!</p>
</div>
</template>
</vaadin-grid>
You can then define a function called _onActiveItemChanged inside your polymer element to handle the active item changed event.
In my index.html I have a paper-scroll-header-panel with a paper-toolbar and a custom element serving as the page content:
<body unresolved>
<template is="dom-bind" id="app">
<paper-scroll-header-panel>
<paper-toolbar class="medium-tall">
...
</paper-toolbar>
<!-- Main Content -->
<div class="content">
<x-content></x-content>
</div>
</paper-scroll-header-panel>
</template>
</body>
In x-content, I have a firebase-collection which I am looping over to show data:
<dom-module id="x-content">
<template>
<firebase-collection
limit-to-first="30"
location="myFirebaseURL"
data="{{items}}"></firebase-collection>
<template is="dom-repeat" items="{{items}}">
<x-item item="{{item}}"></x-item>
</template>
</template>
<script>
Polymer({
is: "x-content",
_loadMoreData: function (e) {
// load more
}
});
</script>
</dom-module>
I want to be able to load more data when the user scrolls. I have tried implementing the iron-scroll-threshold but it is not working. I expect I need to use the scrollTarget attribute to link it to an element which will fire the scroll event but I'm not sure which element I should use.
I have tried setting it to body, document and the paper-scroll-header-panel but none of these are working when I scroll - some are even firing on page load when no scrolling is happening!
Has anyone tried this?
You could try to link to paperScrollHeaderPanel.scroller
and make sure when loading the data function to clear the triggers:
scrollThreshold.clearTriggers();
see this
I'm running into a similar problem as this question.
However, my case is a bit different and I can't seem to get it to work. I've been playing with it for a while an no luck so far.. I need href$="{{_getProject(item.project_id)}}" to be written as "webservices/api/projects/1" but the closest thing I can get is it outputting the item.project_id without being able to concatenate with it so just the 1. I've tried various things but below is what I have most recently. Does anyone have any ideas on how I can get this to work? I'm sure it's something I'm overlooking.
<template is="dom-bind">
<iron-ajax url="<?echo $url?>" last-response="{{data}}" auto></iron-ajax>
<iron-list items="[[data]]" as="item">
<template>
<div>
<div class="item">
<div class="pad">
<div class="primary">[[item.project_name]]</div>
<div class="secondary">Project Deadline:</div>
<div class="secondary">[[item.project_deadline]</div
<div class="secondary">Total Hours to date:</div>
<div class="secondary">[[item.project_total_hours</div>
<div class="secondary">[[item.project_id]]</div>
</div>
<a href$="{{_getProject(item.project_id)}}"><iron-icon icon="assignment"><iron-icon></a>
</div>
</div>
</template>
<script>
Polymer({
_getProject: function(url) {
return 'webservices/api/projects/' + url
}
});
</script>
</iron-list>
</template>
The Polymer({...}) call you have inside of your iron-list won't work as you expect (and it should actually show an error in the console), since you are not defining/can't define a custom element inside of iron-list but only a template that will be stamped.
There are two ways to achieve what you want.
Define a custom element that you use inside of the iron-list
<dom-module id="my-item">
<template>
<div class="item">
...
<a href$="{{_getProject(item.project_id)}}">...</a>
</div>
</template>
<script>
Polymer({
is: 'my-item',
properties: {
item: Object
},
_getProject: function(url) {
return 'webservices/api/projects/' + url
}
});
</script>
</dom-module>
<iron-list items="[[data]]" as="item">
<template>
<my-item item="[[item]]"></my-item>
</template>
</iron-list>
Define the _getProject function on your main template
<template is="dom-bind" id="app">
...
<iron-list items="[[data]]" as="item">
<template>
<div>
<div class="item">
...
<a href$="{{_getProject(item.project_id)}}">...</a>
</div>
</div>
</template>
</iron-list>
</template>
<script>
var app = document.getElementById('app');
app._getProject = function (url) {
return 'webservices/api/projects/' + url
}
</script>
I am am trying to create a custom element that plays a youtube video in paper-dialog. So videoPlayer = Polymer.dom(this.root).querySelector('video-player'); inherits/has access to that paper-dialogs open method, I am trying to extend my custom element. It isn't working, but hopefully I am on the right track and someone can show me correctly.
I am using Polymer 1.0, but I only have https://www.polymer-project.org/0.5/docs/polymer/polymer.html#extending-other-elements to go by for extending elements.
<link rel="import" href="../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../bower_components/google-youtube/google-youtube.html">
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="video-player">
<template>
<div class="layout horizontal">
<paper-button dialog-dismiss>
<paper-icon-button icon="arrow-back"></paper-icon-button>
</paper-button>
</div>
<div style="height: 100%; width: 100%">
<google-youtube style="height: 100%;"
video-id="YMWd7QnXY8E"
rel="1"
start="5"
playsinline="0"
controls="2"
showinfo="0"
width="100%"
height="100%"
autoplay="1">
</google-youtube>
</div>
</template>
<script>
Polymer({
is: "video-player"
});
</script>
<paper-dialog name="video-player" extends="video-player">
<template>
<shadow></shadow>
</template>
<script>
Polymer();
</script>
</paper-dialog>
<video-player></video-player>
As was mentioned in the comments, you can't yet extend custom elements, so the existing pattern (or at least the one I use) is to make use of behaviors wherever possible and wrappers wherever not.
e.g.
<dom-module id="popup-video-player">
<template>
<video-player></video-player>
</template>
<script>
Polymer({
is: 'popup-video-player',
behaviors: [Polymer.PaperDialogBehavior],
...
});
</script>
</dom-module>
Now you can use <popup-video-player> just like a paper-dialog.
I know it stinks because if video-player has a bunch of properties that you want access to, you have to copy them in the popup-video-player element's API, which is not exactly DRY.
If you look at the paper-input source, you'll see them doing the same thing. It's obvious that they want to extend iron-input, but they can't so you get things like this:
<input is="iron-input" id="input"
aria-labelledby$="[[_ariaLabelledBy]]"
aria-describedby$="[[_ariaDescribedBy]]"
disabled$="[[disabled]]"
title$="[[title]]"
... >
As a side note, you could always hook into the <video-player>s "properties" property and make the API additions programatically.
maybe something like this would work: (untested!)
Polymer({
...
properties: (function () {
var prop = {
//special properties specific to the pop up version of video-player
//..obviously be careful to avoid name space conflicts.
};
var video_player = document.createElement('video-player');
video_player.properties.keys().forEach( function(key) {
props[key] = video_player[key];
});
return props;
}()),
});