Polymer preload spinner - html

Sometimes it takes a while for polymer to load, and when using <body unresolved>, the page stays blank until everything is ready. Is there a way to display something between the time that the page is served and the time that polymer is done doing its magic?

The documentation that describes the unresolved attribute clears some of this up.
While it's common to apply unresolved to the <body> element, causing the entirety of your page's content to be hidden until Polymer is ready, it can be applied to any element(s). You can, for instance, use <div unresolved> as a wrapper around the portion of your page that relies on Polymer, and create a loading message that's outside that wrapper which will be visible immediately. (You'd then want to listen to the polymer-ready event and hide your loading message when that's fired.)
Here's an example using a very contrived way of slowing down the time it takes for the Polymer element to complete one of its lifecycle methods (live demo):
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Polymer Demo</title>
<style>
.hidden {
display: none;
}
</style>
</head>
<body>
<p id="spinner">Loading...</p>
<script src="http://www.polymer-project.org/platform.js"></script>
<link rel="import" href="http://www.polymer-project.org/components/polymer/polymer.html">
<polymer-element name="slow-poke">
<template>
<h1><content></content></h1>
</template>
<script>
Polymer({
// Used to introduce a delay in initializing the Polymer element.
// Don't try this at home!
created: function() {
var start = Date.now();
while (true) {
if (Date.now() - start > 1000) {
break;
}
}
}
});
</script>
</polymer-element>
<div unresolved>
<slow-poke>Here I am... finally!</slow-poke>
<slow-poke>Me too!</slow-poke>
</div>
<script>
window.addEventListener('polymer-ready', function() {
document.querySelector('#spinner').classList.add('hidden');
});
</script>
</body>
</html>
(By the way, what are you finding to be slow-loading? If it's a standard/core element, it might be worth filing a bug against the corresponding project on GitHub.)

Related

Handling of loading indicator for multiple ajax calls in Polymer

I'm using Polymer 1.0 to create a web application.
I have various elements doing one or more iron-ajax calls and I have another element for showing the loading-overlay. But in my current sollution I have added the loading-overlay, with its logic to show or not, to every element doing ajax calls.
<dom-module id="backend-call-application">
<template>
<iron-ajax id='loadA' loading="{{_loadingA}}" ...></iron-ajax>
<iron-ajax id='loadB' loading="{{_loadingB}}" ...></iron-ajax>
<loading-overlay id="loadingOverlay" with-backdrop></loading-overlay>
</template>
<script>
Polymer({
is: 'backend-call-application',
observers:[
"_isXhrLoading(_loadingA,_loadingB,....)"
],
_isXhrLoading: function() {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i]) {
this.$.loadingOverlay.open()
return;
}
}
this.$.loadingOverlay.close()
}
});
</script>
</dom-module>
Now my question is, what is the best way to show such a loading-overlay?
One idea of mine would be, to have something like an observer in the loading overlay. So every element doing requests will bind its properties to the observer. These properties could be stored in an array and everytime on change, the loading-overlay checks if at least one have loading properties set to true. When one or more properties are true the loading-overlay will be opened and when all requests finished loading it will be closed.
Another idea was to use events to tell the loading-overlay when a element starts/stops loading. But here will be the problem, that I have more than one request at the same time (The first request closes the overlay, but the page hasn't finished loading).
Edit:
The loading-overlay is an element containing the IronOverlayBehavior.
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/iron-overlay-behavior/iron-overlay-behavior.html">
<link rel="import" href="../../../bower_components/paper-spinner/paper-spinner.html">
<dom-module id="loading-overlay">
<template>
<paper-spinner active="true"></paper-spinner>
</template>
<script>
Polymer({
is: 'loading-overlay',
behaviors: [
Polymer.IronOverlayBehavior
]
});
</script>
</dom-module>
use one property for loading instead of 2!!
<iron-ajax id='loadA' loading="{{_loading}}" ...></iron-ajax>
<iron-ajax id='loadB' loading="{{_loading}}" ...></iron-ajax>
bind loading value to loading-overlay with some attribute and when loading is true display loader
<loading-overlay id="loadingOverlay" is-loading="[[_loading]]" with-backdrop></loading-overlay>
so each time any ajax is made then _loading will become true so displays loader
I think the only thing you could shorten is the _isXhrLoading observer.
_isXhrLoading: function() {
if(Array.from(arguments).indexOf(true) >= 0) {
this.$.loadingOverlay.open()
} else {
this.$.loadingOverlay.close()
}
}

Polymer2.0- Trying to download DIV content of custom element

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

Polymer template and style tag relation

I know that Polymer recommends to use style tag inside template tag since v1.1 but supports both. Can anyone tell me the advantages of doing so. If it is inertness then can you please give an example where keeping style tag outside template exposed it outside of shadow-dom
The 1.1 release notes indicate performance reasons:
Previously, we recommended that a <style> element should be placed inside an element's <dom-module> but outside of its template. This is still supported, but we've now optimized placing styles within the template itself, so having the <style> tag outside of the template will be slower.
If I read the code correctly, this is Polymer's procedure for parsing CSS:
Select child nodes that can contain CSS (including <style> and <template>).
For each node:
a. If the node is <template>, recurse on the node (go to step 1).
b. Else if the node is <style>, remove the node (to prevent style leak), and then append the node's text to the string buffer.
c. Else if the node is <link rel="import" type="css">, append its imported text to the string buffer.
Return the string buffer.
If all styles are parsed using this procedure, I don't understand how the placement of <style> would affect performance (maybe I'm missing something).
please give an example where keeping style tag outside template exposed it outside of shadow-dom
The <style> doesn't leak regardless of whether it's placed inside the <template> (because of step 2b above), as seen in the following demos.
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<div class="title">outside <x-foo> (should not be styled)</div>
<dom-module id="x-foo">
<style>
div.title {
font-family: Arial;
color: blue;
}
</style>
<template>
<div class="title">inside <x-foo></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-foo'
});
});
</script>
</dom-module>
</body>
codepen
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<div class="title">outside <x-foo> (should not be styled)</div>
<dom-module id="x-foo">
<template>
<style>
div.title {
font-family: Arial;
color: blue;
}
</style>
<div class="title">inside <x-foo></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-foo'
});
});
</script>
</dom-module>
</body>
codepen

how to render a raised paper-button with reactjs?

Here is the code that should render a "raised" paper-button:
All the code is in a script tag and renders a paper-button that is not RAISED (see screen shot). I can click and see the RIPPLE effect, seems perfect except the appearance.
UPDATE :
for the moment the only way to get the correct rendering is by replacing
<paper-button raised>test</paper-button>
BY
<div dangerouslySetInnerHTML={{__html: '<paper-button raised>test</paper-button>'}} />
ANY WORKAROUND avoiding this 'dangerous' way?
<!DOCTYPE html>
<html>
<head>
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">
<title>Hello React</title>
<script src="bower_components/react/react.min.js"></script>
<script src="bower_components/react/JSXTransformer.js"></script>
</head>
<body>
<div id="content">
</div>
<script type="text/jsx">
var ButtonT = React.createClass({
render: function() {
return (
<div>
<paper-button raised="true">test</paper-button>
</div>
);
}
});
React.render(
<ButtonT />,
document.getElementById('content')
);
</script>
</body>
</html>
Should the "raised" attribute be passed as a this.props...?
It won't work in the current version of React. Custom attribute support is an open issue, though. For now, I've found this patch works well.
In JSX if you want a custom HTML attribute, you should prefix it with data-, it then will be resolved to actual name without prefix. See docs;

Understanding the constructor attribute in Polymer elements

A Polymer noob...
I'm trying to create a custom element as per the Polymer API docs, where my main page looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Polymer</title>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
</head>
<body>
<div id="test"></div>
<polymer-element name="book-template" constructor="BookTemplate" noscript>
<template>
<style>
h1 { color: orange; }
</style>
<h1>Hello from some-foo</h1>
</template>
</polymer-element>
</body>
</html>
I know that the page content will render if I just put <book-template></book-template> on the page, or if I do something like this inside the <body> tag:
<script>
var book = document.createElement('book-template');
document.getElementById('test').appendChild(book);
</script>
But I'm trying to utilize the element's constructor attribute, assuming that this will create the element when placed somewhere inside of <body>:
<script>
var book = new BookTemplate();
</script>
...but getting a console message that BookTemplate() is not defined.
I'm sure it's something simple...any idea? Thanks in advance.
I guess you have to wait for the polymer-ready event, so that the constructor is available in the global window object http://jsbin.com/kosuf/2/edit?html,console,output:
<script>
document.addEventListener('polymer-ready',function() {
var book = new BookTemplate();
if (book) {
console.log('Ok');
}
});
</script>