Event Handling in Polymer - html

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 {{}}.

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.

In Polymer 1.0 how can I databind to a boolean property of an element?

How can I bind to a boolean property of an element. It seems this
<my-element a-property-of-type-boolean='{{someBoolean}}'></my-element>
does not Work, but I also cant find out how to bind to it when it is exposed like this:
<my-element a-property-of-type-boolean></my-element>
It seems an option is to set the type to Object instead of Boolean, but I am not sure how valid this approach is
Thanks :-)
If you put an attribute on your element, the related property it will always be true. For example in:
<my-element a-property-of-type-boolean='false'></my-element>
a-property-of-type-boolean is true.
So, if you you want to use a Boolean property on your element, I suggest to declare the property with the default value of false and then, if you need to change the value to true, you can add the attribute on you element.
Your Polymer prototype:
Polymer({
is: 'my-element',
properties: {
aPropertyOfTypeBoolean: {
type: Boolean,
value: false
}
}
});
Your element:
<my-element a-property-of-type-boolean></my-element>
As you already figured it out, the behavior of boolean properties has changed in Polymer 1.0 (ref) and now follows the specification of HTML boolean attributes.
You got different solutions to this, but until now I haven't found a clean solution.
As a preface of the solution I'll make a tiny improvement (adding an Id to the problematic element) to your code:
<dom-module id='main-page'>
<template>
<paper-button on-tap='tap'>Click me</paper-button>
<my-element id="myElem" a-property-of-type-boolean></my-element>
<div>In main page it is <div>{{someBoolean}}</div></div>
</template>
</dom-module>
(ref) You could listen to notification's and manually add and remove the attribute from your element (ref).
tap: function() {
if (this.aPropertyOfTypeBoolean) {
Polymer.dom(this.$.myElem).removeAttribute('aPropertyOfTypeBoolean');
} else {
Polymer.dom(this.$.myElem).setAttribute('aPropertyOfTypeBoolean', true);
}
}
If you edit the to use a Boolean attribute you can also set it's property as follows: (it wont reflect in the html unless you use reflectToAttribute: true in the property being defined as Boolean):.
tap: function() {
this.$.myElem.set('aPropertyOfTypeBoolean', Boolean(this.aPropertyOfTypeBoolean));
}
Or you can either hide your element with hidden or template-if solutions.
<template is="dom-if" if="{{someBoolean}}">
<my-element a-property-of-type-boolean></my-element>
</template>
<template is="dom-if" if="{{!someBoolean}}">
<my-element></my-element>
</template>
With hidden
<my-element hidden$="{{someBoolean}}"></my-element>
<my-element a-property-of-type-boolean hidden$="{{!someBoolean}}"></my-element>
Ok, sorry about that guys. I have not done my homework. Everything actually seems to be working exactly as I was hoping for and databinding Works fine. Here is the small example that I did to try and prove my point
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0'>
<meta name='mobile-web-app-capable' content='yes'>
<meta name='apple-mobile-web-app-capable' content='yes'>
<script src='bower_components/webcomponentsjs/webcomponents.js'></script>
<link rel='import' href='bower_components/polymer/polymer.html'>
</head>
<body>
<dom-module id='my-element'>
<template>
<div>In my element it is <div>{{aPropertyOfTypeBoolean}}</div></div>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
aPropertyOfTypeBoolean: {
type: Boolean,
value: false,
}
}
});
</script>
<dom-module id='main-page'>
<template>
<paper-button on-tap='tap'>Click me</paper-button>
<my-element a-property-of-type-boolean='{{someBoolean}}'></my-element>
<div>In main page it is <div>{{someBoolean}}</div></div>
</template>
</dom-module>
<script>
Polymer({
is: 'main-page',
properties: {
someBoolean: {
type: Boolean,
value: false
}
},
tap: function(){
this.someBoolean = !this.someBoolean;
}
});
</script>
<main-page></main-page>
Add $ at the end of it:
<my-element a-property-of-type-boolean$='{{someBoolean}}'></my-element>

Polymer 1.0 services issue

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.

Setting src of <img> in a Polymer Element

Below is the code for my polymer element
I have tried normal dom binding with and everything works fine
The src of the img however does not work.
I checked the html in chrome dev tools and it showed the src all wrong
The src here says /img/12.jpg which means the image is in the folder the html file is in
It however refers to the root of the folder instead
Expected src in dev tools: http://localhost:3000/elements/image-hover/img/12.jpg
Observed src: img/12.jpg
What can I do insted of harcoding it to the expected src?
<dom-module id="image-hover">
<template>
<img src="{{imgsrc}}"/>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'image-hover',
properties: {
imgsrc: {
type: String,
value: 'img/12.jpg'
}
}
});
})();
</script>
Edit: I have solved this issue by using the content tag provided by polymer.
<content id="image" select="img"></content>
The question still remains how can I figure out the source of the folder the element is in.
You can do the following:
<dom-module id="image-hover">
<template>
<img src="{{imgsrc}}"/>
</template>
</dom-module>
<script>
Polymer({
is: 'image-hover',
properties: {
imgsrc: {
type: String,
value: function () {
return location.host + "/img/12.jpg";
}
}
}
});
</script>
The value is now a function that returns a String using the location object. More information can be found on that here. Put simply, it contains information about the current URL.
You can use this.resolveUrl as follows:
properties: {
imgsrc: {
type: String,
value: function() {return this.resolveUrl('img/12.jpg')}
}
}

Polymer: how to parse the index to the elements using template repeat

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.