I am trying to display a toast when an ajax request fails using core-ajax and paper-toast elements. I created an handler that calls show on the paper-toast element. However it is still not showing...
What am I doing wrong?
Is there a better way to do that? (Maybe having the same toast element for all the application messages)
Here it follows my custom element code:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/core-ajax/core-ajax.html">
<link rel="import" href="../bower_components/paper-toast/paper-toast.html">
<polymer-element name="fd-rest-element-service" attributes="fditems fdtype">
<template>
<style>
:host {
display: block;
}
paper-toast {
z-index: 1000;
bottom: 40px;
left: 10px;
}
</style>
<paper-toast id="toast" text="There was a problem loading {{fdtype}} data.">
</paper-toast>
<core-ajax id="ajax"
auto on-core-error="{{errorHandler}}"
url="https://wrong.url.com:9113/{{fdtype}}/"
disabled-on-core-response="{{elementsLoaded}}"
response="{{fditems}}"
handleAs="json" withCredentials >
</core-ajax>
</template>
<script>
Polymer('fd-rest-element-service', {
fdtype:'environments',
created: function() {
this.fditems = [];
},
elementsLoaded: function() {
// Make a copy of the loaded data
console.log(this.fdtype +" : "+ this.$.ajax.response);
this.fditems = this.$.ajax.response.slice(0);
},
errorHandler: function(event){
console.log(event);
console.log(this.$.toast);
this.$.toast.show();
}
});
</script>
</polymer-element>
Since I have got no console error and the logged objects are as expected I believe the problem arises because the element is used inside an element managed by core-animated-pages that is not displayed. Any suggestion on how to create a shared toast element that can be accessed by the other elements in my application?
I ended up creating the paper-toast element inside the outmost element and then pass it through the children element via a toast attribute.
Here it follows some sample code. In my root element I created a paper-toast element referenced by id and share "top-down" in the other inner elements.
<paper-toast
id="toast"
text="There was a problem loading data.">
</paper-toast>
<fow-login user="{{user}}" userPhoto="{{userPhoto}}"
class="loginButton"
toast="{{$.toast}}"
token="{{token}}">
</fow-login>
In my inner element I use it like this:
<polymer-element name="fow-login" attributes="toast user userPhoto globals appID token">
...
<script>
...
loginFail: function(event){
console.log("Error:", event);
if(this.toast){
this.toast.text="There was a login problem.";
this.toast.show();
}
},
...
</script>
</polymer-element>
Related
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()
}
}
I'm using polymer 1.2.1
I'm trying to create two polymer elements paper-button & paper-input.
I had imported following in head
<script src="third-party/js/bower/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="third-party/html/bower/polymer/polymer.html">
<link rel="import" href="third-party/html/bower/paper-button/paper-button.html">
<link rel="import" href="third-party/html/bower/paper-input/paper-input.html">
and added following in body
<paper-button>Flat button</paper-button>
<paper-button raised>Raised button</paper-button>
<paper-button noink>No ripple effect</paper-button>
<paper-button toggles>Toggle-able button</paper-button>
<paper-input label="total">
<div prefix>$</div>
<paper-icon-button suffix icon="clear"></paper-icon-button>
</paper-input>
<script>
Polymer({
is: "paper-button",
// add a callback to the element's prototype
created: function() {
console.log("inside pol1");
this.textContent = "I'm a proto-element!"
}
});
Polymer({
is: "paper-input",
// add a callback to the element's prototype
created: function() {
console.log("inside pol2");
this.textContent = "I'm a proto-elemente2!"
}
});
</script>
I'm expecting a change in text of respective elements with some console but none of these happens. I get an error saying
"Uncaught NotSupportedError: Failed to execute 'registerElement' on 'Document': Registration failed for type 'paper-button'. A type with that name is already registered."
I'm not quite sure what you are trying to achieve, but the answer to your question is this:
Your paper-input and paper-button have already been registered into Polymer by your <link rel="import"> tags in your <head> section, so naturally when you try to re-register them using Polymer({is:"paper-button"...}), it fails...
I also wouldn't recommend overriding a packaged element's created() callback - if you want to do your own custom tasks, create a new custom element that wraps your target element, and then call your new element instead.
We have a custom element that is making an AJAX call to fetch some html generated on the server side and then injected into its light dom via Polymer.dom(this).innerHTML. The response coming from the server has another custom element in it that exposes a CSS property for theming purposes. On the main page, we're setting the value for the property, but it doesn't appear to be working. How do we get Polymer to style dynamically added light DOM elements that are distributed by another element.
index.html
<style is="custom-style">
x-bar {
--mixin-property: {
background: red;
};
}
</style>
...
<body>
<x-baz>
</x-baz>
</body>
x-baz.html
<dom-module id="x-baz">
<template>
<x-foo></x-foo>
</template>
</dom-module>
<script>
Polymer({
is: "x-baz"
});
</script>
x-foo.html
<dom-module id="x-foo">
<template>
<iron-ajax auto url="..." last-response="{{response}}"></iron-ajax>
<content></content>
</template>
</dom-module>
<script>
Polymer({
is: "x-foo",
properties: {
response: {
type: String,
obeserver: 'responseChanged'
}
},
responseChanged: function(newVal)
Polymer.dom(this).innerHTML = newVal;
}
});
</script>
x-bar.html
<dom-module id="x-bar">
<style>
.elementToStyle {
#apply(--mixin-property);
}
</style>
<template>
<div class="elementToStyle">
...
</div>
</template>
</dom-module>
</script>
Polymer({
is: "x-bar"
});
</script>
The iron-ajax call returns <x-bar> ... </x-bar>.
I would expect the div inside the x-bar that comes back from the AJAX response to have a red background, but it doesn't seem to be working. What do we need to adjust to make this work correctly?
Thanks in advance!
I'm trying to use core-list extension from polymer.
I used example from Google Developers from This YT Link
I add is="auto-binding" value to my template i go error:
Uncaught TypeError: Cannot set property 'data' of null
I'm also trying to set height: 100% to core-list , it's also not working , I got warning:
core-list must either be sized or be inside an overflow:auto div that is sized
Below I'm adding my code:
<link rel="import" href="../bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="../bower_components/core-list/core-list.html">
<link rel="import" href="../bower_components/core-pages/core-pages.html">
<link rel="import" href="../bower_components/core-ajax/core-ajax.html">
<!--{{hash}-->
<polymer-element name="progress-page" attributes="hash">
<template>
<template is="auto-binding" id="app" style=" height:100%; overflow: auto;">
<core-list data="{{data}}" flex style=" height:100%;">
<template>
<div class="row" layout horizontal center>
<div data-index="{{index}}">{{model.name}}</div>
</div>
</template>
</core-list>
</template>
</template>
<script>
Polymer('progress-page', {
ready: function () {
this.selected = 0;
var app = document.querySelector('#app');
app.data = generateContacts();
function generateContacts() {
var data = [];
for (var i = 0; i < 1000; i++) {
data.push({
name: 'dddd',
string: 'asd'
});
}
return data;
}
}
});
</script>
</polymer-element>
Cam somebody please tell me what's wrong ? This is 1:1 version from link I've added.
You shouldn't be using template is="auto-binding" inside a Polymer element. The whole point of an autobinding template is that it allows you to set up data binding outside a Polymer element.
So you're combining two concepts here. These two lines are what you'd use if you were using an auto-binding template in your main page:
var app = document.querySelector('#app');
app.data = generateContacts();
Here you're trying to retrieve a reference to the auto-binding template and add a data property to it.
This won't work in your context. '#app' is inside <progress-page>'s shadow DOM, so document.querySelector won't find it.
This line, on the other hand, is adding a property to the <progress-page> element, which is the proper thing to do if you're using core-list inside an element:
this.selected = 0;
So if you want to use an auto-binding template, eliminate the Polymer element and use the first approach (querySelector and assign app.data, app.selected).
If you want to create a Polymer element, eliminate the auto-binding template and use the second approach:
this.data = generateContacts();
this.selected = 0;
Here's a working version of this code with the auto-binding template removed:
http://jsbin.com/lofega/2/edit
I've been trying to use Polymer for a project I'm working on. And although I enjoyed it quite a lot so far, I ran into a problem I just can't solve.
I dumped it down to a simple example. Basically it's just a list element (item-list) that contains item elements (item-card) and i want to parse the items position to the element via the attribute pos. But for some reason the items attribute is allways undefined! Is this because the attribute is bound to the variable i, which dies after the template repeat? If so, how do I work around it? Is there a different approach I should be using here?
SOLUTION: You can find the solution by reading through all the comments, but to sum it up: apperantly there was a timing issue and the attribute wasn't ready at the ready callback. But I found out about the domReady callback (polymer lifecycle documentation). Using domReady it works just fine! Thanks to Günter Zöchbauer for the help!
This is the item-list.html:
<link rel="import" href="components/polymer/polymer.html">
<link rel="import" href="item-card.html">
<polymer-element name="item-list">
<template>
<style>
</style>
<template repeat="{{values, i in data.data}}">
<item-card pos="{{i}}"></item-card>
</template>
</template>
<script>
Polymer({
created: function()
{
this.num = 123456;
this.data = { "data":
[
{
"value":999
},
{
"value":666
},
{
"value":555
},
{
"value":222
}
]
};
}
});
</script>
</polymer-element>
This is the item-card.html
<link rel="import" href="components/polymer/polymer.html">
<polymer-element name="item-card" attributes="pos">
<template>
<style>
</style>
</template>
<script>
Polymer({
ready: function()
{
console.log("ready: " + this.pos);
}
});
</script>
</polymer-element>
I didn't bother putting the index.html in, since it just containts one item-list element.
Thanks alot!!
I think you need a pos field in <item-card> in addition to the attributes="pos" declaration.
The repeated element also references the bound model which can be accessed like querySelector('item-card').templateInstance.model property.
See https://github.com/PolymerLabs/polymer-selector/blob/master/polymer-selector.html#L286 for an example.
Info:
According to the comments it turned out to be a timing issue. The value wasn't yet assigned when the ready callback was called but using domReady worked.