Polymer 1.0 services issue - polymer

I'm working on a reddit client using polymer to check out web compoments technologies. I started with the 0.5 version and got back on this project recently. That when I found out that polymer had the 1.0 released so I started over (as it wasn't that advanced anyway).
I have a service that use the iron-ajax to request reddit api and look for the posts. Here is the code :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<dom-module id="reddit-list-service">
<template>
<iron-ajax
url='https://www.reddit.com/new.json'
handle-as='json'
debounce-duration="300"
on-response='handleResponse'
debounce-duration="300"
auto>
</iron-ajax>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'reddit-list-service',
properties: {
modhash: {
type: String,
value: function() {
return '';
}
},
posts: {
type: Array,
value: function () {
return [];
}
},
after: {
type: String,
value: function () {
return '';
}
}
},
// Update object properties from the ajax call response
handleResponse: function (resp) {
this.properties.modash = resp.detail.response.data.modhash;
this.properties.posts = resp.detail.response.data.children;
this.properties.after = resp.detail.response.data.after;
this.post = this.properties.posts; // just to try
console.log(this.properties.posts);
}
});
})();
</script>
My log shows me that I get posts from the API and that's great!
Here's the issue when I want to use this service to make a list out of the posts array I can't figure out how to get them into my list compoment which is below :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../reddit-list-service/reddit-list-service.html">
<dom-module id="reddit-post-list">
<template>
<reddit-list-service posts="{{posts}}">
</reddit-list-service>
<template is="dom-repeat" id="post-list" posts="{{posts}}">
<p>{{post.author}}</p>
<template>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'reddit-post-list',
properties: {
},
});
})();
</script>
I've tried several think I saw in the documentation but I can't figure out what's wrong the author property doesn't show up.
Any clue?

You have a few things that aren't quite right here. In reddit-post-list you are not using the dom-repeat template correctly. See below:
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="reddit-list-service.html">
<dom-module id="reddit-post-list">
<template>
<reddit-list-service posts="{{posts}}"></reddit-list-service>
<template is="dom-repeat" items="[[posts]]">
<p>{{item.data.author}}</p>
</template>
</template>
</dom-module>
<script>
Polymer({
is: "reddit-post-list"
});
</script>
You need an attribute called items which is the array the dom-repeat will iterate over. Inside the iteration you need to refer to item as this is the array item for the current iteration. Here are the docs.
For you reddit-list-service, you need to set the the reflectToAttribute and notify attributes to true on your posts property. This means that any changes to this property are reflected back on the posts attribute on the reddit-list-service element. See here for more information.
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/iron-ajax/iron-ajax.html">
<dom-module id="reddit-list-service">
<template>
<iron-ajax auto url="https://www.reddit.com/new.json" handle-as="json" on-response="handleResponse"></iron-ajax>
</template>
</dom-module>
<script>
Polymer({
is: "reddit-list-service",
properties: {
modhash: {
type: String,
value: ""
},
posts: {
type: Array,
value: function () {
return [];
},
reflectToAttribute: true, // note these two new attributes
notify: true
},
after: {
type: String,
value: ""
}
},
// Update object properties from the ajax call response
handleResponse: function (resp) {
this.modash = resp.detail.response.data.modhash;
this.posts = resp.detail.response.data.children;
this.after = resp.detail.response.data.after;
}
});
</script>
I have also tidied up the following things:
Removed the immediately called function wrapper from the <script> tags as these are not needed.
When referring to properties in your element you only need to use this.PROPERTYNAME rather than this.properties.PROPERTYNAME.
Having looked at the JSON returned, it appears that the author property is on the another property called data.
When you declare a value for a property in your element, you only need to have a function that returns a value if the property type is an Object or Array.

Related

signedIn property of domHost is false on ready function call

I want to check if the user is logged in on element creation and eventually redirect him if the user is not. The problem is that the domHost.signedIn property is false even though the user is signedIn. If I check the property later(for example when I call a function with button tap) the property is true as it should be.
Here is the code:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/paper-button/paper-button.html">
<dom-module id="settings-view">
<template>
<style>
</style>
TODO: user settings
<paper-button on-tap="debugFunction">button</paper-button>
</template>
<script>
Polymer({
is: 'settings-view',
ready: function () {
console.log(this.domHost.signedIn); // false
console.log(this.domHost.user); // null
},
debugFunction: function () {
console.log(this.domHost.signedIn); // true
console.log(this.domHost.user); // user object
}
});
</script>
</dom-module>
What is the best way to check if the user is signedIn in child element? Would setting the signedIn value to iron-meta element be a better approach?
Thanks, Jan
You're better off declaring properties with observers on them. Observers will execute the function as soon as the property's value is something other than undefined. So your code will look like this:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/paper-button/paper-button.html">
<dom-module id="settings-view">
<template>
<style>
</style>
TODO: user settings
</template>
<script>
Polymer({
is: 'settings-view',
properties: {
signedIn: {
type: Boolean,
observer: '_signedInChanged'
},
user: {
type: Object,
observer: '_userChanged'
},
},
_signedInChanged: function (newSignedInValue) {
console.log(newSignedInValue); // true
console.log(this.signedIn); // true
},
_userChanged: function (newUserValue) {
console.log(newUserValue); // user object
console.log(this.user); // user object
}
});
</script>
</dom-module>
Then when you update those signedIn and user values through JavaScript or data binding, the observers will call the associated functions.

I have an iron-ajax with an object response, but the name is dynamic

The thing is that this object name changes from an array list, and i dont really understand how could i bind them. I want to extract the id from the response and profileIconId. It would be simple for one user, but i have a lot of them. Thank you in advance for the help!
This is my code:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="shared-styles.html">
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">
<dom-module id="my-summoner">
<template>
<style>
:host {
display: block;
}
</style>
<iron-ajax
auto
url="[[_summonerName(name)]]"
handle-as="json"
last-response="{{names}}"></iron-ajax>
<h1>[[name]]</h1>
<span>{{names.~dynamic user name~.name}}</span>
</template>
<script>
Polymer({
is: 'my-summoner',
properties: {
name: {
type: String,
value: '',
notify: true
},
},
_summonerName: function(name){
return 'https://api.leagueofzabalt.club/summoner/by-name/' + name;
}
});
</script>
</dom-module>
This is the response:
{"lordfumeitor": {
"id": 19347567,
"name": "lord fumeitor",
"profileIconId": 1385,
"revisionDate": 1479073568000,
"summonerLevel": 30
}}
It seems that iron-ajax doesn't know how to handle objects as responses. The one work-around is to use the results value in the api return and force it into a dom repeat template, since it corresponds with an array, albeit of a single object. The response would look something like this:
results: [
{
"lordfumeitor": {
"id": 19347567,
"name": "lord fumeitor",
"profileIconId": 1385,
"revisionDate": 1479073568000,
"summonerLevel": 30
}
}
]
Assuming you're grabbing name from the element like so:
<my-summoner name="lordfumeitor"></my-summoner>
You would then be able to grab the returned data and output it to a template:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="shared-styles.html">
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">
<dom-module id="my-summoner">
<template>
<style>
:host {
display: block;
}
</style>
<iron-ajax
auto
url="[[_summonerName(name)]]"
handle-as="json"
on-response="responseHandler">
</iron-ajax>
<template is="dom-repeat" items=[[data]]>
<h1>[[data.name]]</h1>
<span>[[data.name.id]]</span>
<span>[[data.name.profileIconId]]</span>
</template>
</template>
<script>
Polymer({
is: 'my-summoner',
properties: {
name: String,
},
created: function() {
name = this.getAttribute('name');
},
_summonerName: function(name){
return 'https://api.leagueofzabalt.club/summoner/by-name/' + name;
},
responseHandler: function(request) {
data = JSON.parse(request.detail.response);
return this.data = data.results;
}
});
</script>
</dom-module>

Event Handling in Polymer

I have switch.html like this:
<link rel="import" href="/public/components/paper-toggle-button/paper-toggle-button.html">
<dom-module id="element-name">
<template>
<div><paper-toggle-button on-change="{{handleToggle}}"></paper-toggle-button></div>
</template>
<script>
// element registration
Polymer({
is: "element-name",
properties: {
greeting: {
type: String,
value: "Hello!"
}
},
handleToggle: function() {
alert('Ow!')
}
});
</script>
</dom-module>
version: 1.2.0
How do I catch change event and handle it? I have set on-change property, but it does not work. Next, I need to send json to my server.
You have wrapped handleToggle in curly braces which makes it a binding. Just remove them to tell on-change to call a function:
<paper-toggle-button on-change="handleToggle"></paper-toggle-button>
Did you try this:
on-change="handleToggle"
handleToggle is not a property, so you do not have to use {{}}.

iron-media-query doesn't work - Polymer 1.0

I'm new to Polymer (1.0).
My <iron-media-query> element is not working. No errors in the console but it does not display anything.
Some improvements would be awesome! I'm trying to get it up and running since 2 hours. :)
Thanks in advance
Ron
<!-- Works correctly -->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-media-query/iron-media-query.html">
<dom-module id="custom-element">
<style>
// Styles here
</style>
<template>
<iron-media-query query="{{query}}" queryMatches="{{smallScreen}}"></iron-media-query>
<template if="{{smallScreen}}">
<strong>Small Screen</strong>
</template>
<template if="{{!smallScreen}}">
<strong>Big Screen</strong>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'custom-element',
properties: {
query: {
type: String,
notify: true
}
}
});
</script>
<custom-element query="(max-width:400px)"></custom-element>
You have to change queryMatches="{{}}" to query-matches="{{}}".
Since you also asked about optmizations:
Since you don't have a massive difference in the data between SmallScreen and not, so:
<strong>[[screenType]] Screen</strong>
<script>
Polymer({
is: 'custom-element',
properties: {
query: {
type: String,
notify: true
},
screenType: {type: String, computed: '_computeScreenType(smallScreen)'}
},
_computeScreenType: (t)=>{return t?"Small":"Big"}
});
</script>

Polymer: How to loop and render HTML to screen

I am working on a widget that pulls third party information from a database using json. Once the information has been collected, I plan to loop through the information and create the required HTML code and insert this into the template via a {{variable}}
Now I am getting an unexpected result. When I do this, the html is being displayed as text.
Here is some sudo code of the issue:
<polymer-element name="loop-element">
<template>
{{customerList}}
</template>
<script>
Polymer('loop-element', {
ready: function() {
this.loadCustomerList();
}
customerList:"Loading customer list...",
loadCustomerList: function() {
CustomerNameArray[] = //Get the array from jSon file
i = 0;
do {
this.customerList = "<div>" + customerNameArray[i] + "</div>";
} while (customerNameArray[i]);
}
});
</script>
</polymer-element>
Essentially the DIV's are not being rendered, instead they are being printed to the screen as text:
"<div>Name 1</div>" "<div>Name 2</div>" ... n
Instead of:
Name 1
Name 2
Name n...
You can see a JSBin example here: http://jsbin.com/tituzibu/1/edit
Can anyone recommend how to go about outputting a list to the template?
Polymer v.1.0
/* relative path to polymer.html*/
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="employee-list">
<style>
/* CSS rules for your element */
</style>
<template>
<div> Employee list: </div>
<template is="dom-repeat" items="{{employees}}">
<div>First name: <span>{{item.first}}</span></div>
<div>Last name: <span>{{item.last}}</span></div>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'employee-list',
ready: function() {
this.employees = [
{first: 'Bob', last: 'Smith'},
{first: 'Sally', last: 'Johnson'}
];
}
});
</script>
doc
You should use Polymer's DOM-based data-binding features rather than creating the markup yourself.
<template repeat="{{customer, i in customers}}">
<div>{{i}}, {{customer.name}}</div>
</template>
http://www.polymer-project.org/docs/polymer/databinding.html#an-example
Maybe a little late...
If you want to stick to your approach you could use this.injectBoundHTML:
<polymer-element name="loop-element">
<template>
<div id='customerList'> </div>
</template>
<script>
Polymer('loop-element', {
ready: function() {
this.loadCustomerList();
}
customerList:"Loading customer list...",
loadCustomerList: function() {
CustomerNameArray[] = //Get the array from jSon file
i = 0;
do {
this.customerList = "<div>" + customerNameArray[i] + "</div>";
} while (customerNameArray[i]);
this.injectBoundHTML( this.customerList,
this.$.customerList);
}
});
</script>
</polymer-element>
However the first approach is better..
In Polymer 3.0 you can do the following:
<dom-repeat items="{{customers}}">
<template>
{{item.name}}
</template>
</dom-repeat>
Any list is binded to the items property of dom-repeat, and item within the template is used to represent the object from the list. You can read more about the dom-repeat on the Polymer 3.0 API reference page here.