Polymer ondblclick not working - polymer

I am trying to use ondblclick inside polymer element, but I cannot get it to work.
I know that I can just use ondblclick="someFunction()" but I need to access double clicked element model, something like on-tap event:
event.target.templateInstance.model.myModel;
<script src="http://www.polymer-project.org/platform.js"></script>
<script src="http://www.polymer-project.org/polymer.js"></script>
<polymer-element name="dblclick-test">
<template>
<button on-dblclick="{{btnDblClick}}" on-tap="{{btnTap}}">{{btnText}}</button>
</template>
<script>
Polymer({
btnText: 'double click me',
btnDblClick: function(event) {
// in real code I need to use
// event.target.templateInstance.model
// just like on-tap's event param
this.btnText = 'Hi, u dbl clicked me !!!!!!';
},
btnTap: function(event) {
this.btnText = 'Hi, u clicked me !';
}
})
</script>
</polymer-element>
<dblclick-test></dblclick-test>
Is there any polymeric way to do it?

First
I was missing the declarative event mapping by using ondbleclick instead of on-dblclick, thanks to ebidel edit to my question.
Even though the above example won't work.
Second
To solve the conflict between on-tap and on-dblclick, I used something like the following in my code:
<script src="http://www.polymer-project.org/platform.js"></script>
<script src="http://www.polymer-project.org/polymer.js"></script>
<polymer-element name="dblclick-test">
<template>
<button on-tap="{{btnTap}}">{{btnText}}</button>
</template>
<script>
Polymer({
btnText: 'double click me',
btnDblClick: function(event) {
this.btnText = 'Hi, u dbl clicked me !!!!!!';
},
btnTap: function(event) {
if (this.tappedOneTime) {
this.btnDblClick();
this.tappedOneTime = false;
} else {
this.btnText = 'Hi, u clicked me !';
}
this.tappedOneTime = true;
// reset flag after 800ms
this.async(function() {
this.tappedOneTime = false;
}, null, 800);
}
})
</script>
</polymer-element>
<dblclick-test></dblclick-test>

I assume tap is also fired on dblclick this makes it difficult.
My (and other answers) to this question Distinguish between onClick and onDoubleClick on same element to perform different actions in Dart show possible solutions.

Don't use on-tap and on-dblclick together, if you need both behaviors use on-click instead on-tap.
<my-elem on-click="clicked" on-dblclick="dblclicked">

Related

Polymer listen to events from child light DOM

is it possible for a parent element to listen to events from light DOM children? My setup does not seem to be working.
<dom-module id="sm-tabs">
<template>
<sm-redux-store>
<button on-click="handleDispatchClick">Dispatch action</button>
</sm-redux-store>
</template>
<script src="../../dist/tabs.component.js"></script>
</dom-module>
I want sm-redux-store to listen to an event that I call from the handleDispatchClick function. Here is the function:
const handleDispatchClick = function(e) {
this.fire('dispatch', {
action: {
type: 'CHANGE_TEMP',
newTemp: 'temporary data'
};
});
};
In my script for sm-redux-store, I have this listener object:
const listeners = {
'dispatch': 'handleDispatch'
};
sm-redux-store never handles the event raised from the button click, and I'm not sure why.
I think I just figured out what was wrong. Inside of handleDispatchClick, this is bound to the parent element. The parent element is sm-tabs, not sm-redux-store. I just need to wrap sm-tabs with sm-redux-store outside of the template, and it works.

Remove child element's attribute from Polymer js

I've a custom element which, among other things, has a core-input and a paper button in it.
When the element is created, the input is disabled, and I want to enable it when I tap the button.
I've tried several ways and can't access the input's attribute.
<paper-input-decorator label="Nombre de usuario" floatingLabel>
<input id="usernameinput" value="{{UserName}}" is="core-input" disabled />
</paper-input-decorator>
<paper-button raised id="edprobutton" on-tap="{{edbutTapped}}">EDITAR</paper-button>
What should I write in
edbutTapped: function () {
},
EDIT
So, I've learned that the problem was that my username input element was inside a repeat template, and that's bad for what I was trying to do. Now I'm trying to bind a single json object to my element, with no luck so far.
What I have right now:
In my Index page:
<profile-page id="profpage" isProfile="true" entity="{{profEntity}}"></profile-page>
<script>
$(document).ready(function () {
var maintemplate = document.querySelector('#fulltemplate');
$.getJSON('api/userProfile.json', function (data) {
var jsonString = JSON.stringify(data);
alert(jsonString);
maintemplate.profEntity = jsonString;
});
}
</script>
In my element's page:
<polymer-element name="profile-page" attributes="isprofile entity">
<template>
<style>
[...]
</style>
<div flex vertical layout>
<core-label class="namepro">{{entity.Name}}</core-label>
<core-label class="subpro">{{entity.CompanyPosition}}</core-label>
<core-label class="subpro">{{entity.OrgUnitName}}</core-label>
</div>
</template>
</polymer-element>
And my JSON looks like this:
{"Name": "Sara Alvarez","CompanyPosition": "Desarrollo","OrgUnitName": "N-Adviser"}
I'm asuming I need to "update" my element somehow after changing its entity attribute?
Try the following
<script>
Polymer({
edbutTapped: function () {
this.$.usernameinput.disabled = false;
}
});
</script>
The this.$ allows you to access controls defined in an elements and the usernameinput is the id you assigned to the input.
This can go below the closing tag of the element you are defining.
'disabled' is conditional-attribute.
So this will be the correct use of it:
<input id="usernameinput" value="{{UserName}}" is="core-input" disabled?="{{isDisabled}}" />
In the prototype:
//first disable the field, can be done in ready callback:
ready: function () {
this.isDisabled = 'true';
}
//set idDisabled to 'false' i.e. enable the input
edbutTapped: function () {
this.isDisabled = 'false';
},
OK this is going to be a long answer (hence why I am not entering this as an edit of my original answer). I've just done something which is functionally the same.
The first thing is this code;
$.getJSON('api/userProfile.json', function (data) {
var jsonString = JSON.stringify(data);
alert(jsonString);
maintemplate.profEntity = jsonString;
});
Polymer has a control called core-ajax - this as it's name suggests makes an ajax call. The other really nice thing is that it can be made to execute when the URL changes. This is the code from the project I've got.
<core-ajax id="ajax"
auto=true
method="POST"
url="/RoutingMapHandler.php?Command=retrieve&Id=all"
response="{{response}}"
handleas="json"
on-core-error="{{handleError}}"
on-core-response="{{handleResponse}}">
</core-ajax>
The auto is the bit which tells it to fire when the URL changes. The description of auto from the polymer documentation is as follows;
With auto set to true, the element performs a request whenever its
url, params or body properties are changed.
you don't need the on-core-response but the on-core-error might be more useful. For my code response contains the JSON returned.
So for your code - it would be something like this
<core-ajax id="ajax"
auto=true
method="POST"
url="/api/userProfile.json"
response="{{jsonString}}"
handleas="json"
on-core-error="{{handleError}}" >
</core-ajax>
Now we have the data coming into your project we need to handle this. This is done by making use of Polymer's data-binding.
Lets detour to the element you are creating. Cannot see anything wrong with the following line.
<polymer-element name="profile-page" attributes="isprofile entity">
We have an element called 'profile-page' with two properties 'isprofile' and 'entity'.
Only because my Javascript leaves a bit to be desired I would pass each property as a seperate entity making that line
<polymer-element name="profile-page" attributes="isprofile name companyposition OrgUnitName">
Then at the bottom of your element define a script tag
<script>
Polymer({
name: "",
companyposition: "",
OrgUnitName: ""
});
</script>
Now back to the calling (profile-page). The following code (from my project) has the following;
<template repeat="{{m in response.data}}">
<map-list-element mapname="{{m.mapName}}" recordid="{{m.Id}}" on-show-settings="{{showSettings}}">
</map-list-element>
</template>
Here we repeat the following each element. In your case you only have one entry and it is stored in jsonString so your template is something like this
<template repeat="{{u in jsonString}}">
<profile-page name="{{u.name}} companyposition="{{u.companyposition}}" OrgUnitName="{{u.OrgUnitName}}">
</profile-page>
</template>
Now we get to the issue you have. Return to your profie-page element. Nothing wrong with the line
on-tap="{{edbutTapped}}"
This calls a function called edbutTapped. Taking the code I gave you earlier
<script>
Polymer({
edbutTapped: function () {
this.$.usernameinput.disabled = false;
}
});
</script>
The only thing to change here is add the following code
created: function() {
this.$.usernameinput.disabled = true;
},
This is inserted after the Polymer({ line. I cannot see in your revised code where the usernameinput is defined but I am assuming you have not posted it and it is defined in the element.
And you should be working, but remember to keep your case consistent and to be honest I've not been - certain parts of Polymer are case sensitive - that catches me out all the time :)

Control a paper-checkbox's state

I'm trying to setup an element with a paper-checkbox inside of it. I want the checkbox's checked state to be controlled by the response of an ajax call.
HTML:
<epic-list-episode checked="<%= episode.seen? %>">
<p><strong><%= episode.show.name %></strong></p>
</epic-list-episode>
Custom element:
<polymer-element name="epic-list-episode" attributes="checked">
<template>
<link rel="stylesheet" href="epic-list-episode.css.scss" />
<div horizontal layout center>
<div flex>
<content></content>
</div>
<div vertical layout>
<paper-checkbox checked?="{{checked === 'true'}}" on-change="{{changeHandler}}"></paper-checkbox>
</div>
</div>
</template>
<script>
Polymer({
changeHandler: function(event) {
//Send ajax, wait for error/success callback
//checkbox.checked = response from ajax
}
});
</script>
</polymer-element>
How can this be achieved? I've tried return false but the checkbox still does its toggle animation.
To clarify, here is the flow i want:
Checkbox is unchecked
I click the checkbox (I don't want it to toggle yet)
Ajax request is sent off
Wait for the callback
If it's successful, toggle the state of the checkbox
I don't think you need that checked attribute at all.
What you can do is, when the on-change is called, set the checked property of the paper-checkbox back to its previous value. And then after the ajax callback, set it back to what it should be.
changeHandler: function (event, detail, sender) {
this.$.checkbox.checked = !this.$.checkbox.checked;
// give the checkbox a little loading animation
var loading = new CoreAnimation();
loading.duration = 750;
loading.easing = 'ease-in';
loading.keyframes = [{ opacity: 1, transform: "scale(1)" }, { opacity: 0.4, transform: "scale(0.9)" }];
loading.direction = 'alternate';
loading.iterations = '1000';
loading.target = this.$.checkbox;
loading.play();
// give it a little delay to act like a callback
this.job('delay', function () {
// stop the animation
loading.finish();
this.$.checkbox.checked = !this.$.checkbox.checked;
}, 3000);
}
Note that I have also included some animation code to make the user feel like the paper-checkbox is doing something, for a better user experience. Please see this jsbin for a working example.
there are a few ways to actually go about it. i have made this plunker to show the 2 ways i go about doing this. http://plnkr.co/edit/xqHCSvs63u4bdFJYM6TF?p=preview
using declarative binding
<paper-checkbox checked="{{checked}}" on-change="{{changeHandler}}"></paper-checkbox>
in your script
this.checked = true;
and pure js
<paper-checkbox id="box" on-change="{{changeHandler}}"></paper-checkbox>
then in your script
var box = document.querySelector("#box");
box.checked = true;

How do I put the selected core-menu item into a custom polymer element?

I'm trying to encapsulate a paper-dropdown in a paper-button. To do this, I made a custom element, paper-dropdown-holder:
<polymer-element name="paper-dropdown-holder" extends="paper-button" relative on-tap="{{toggle}}">
<template>
<shadow></shadow>
<content></content>
</template>
<script>
Polymer({
toggle: function() {
if (!this.dropdown) {
this.dropdown = this.querySelector('paper-dropdown');
}
this.dropdown && this.dropdown.toggle();
}
});
</script>
</polymer-element>
and I'm using it in the page like:
<paper-dropdown-holder raised tabindex="0" class="unpadded">
<paper-dropdown class="dropdown" flex>
<core-menu class="menu" selected="0">
<paper-item>Writing</paper-item>
<paper-item>Blog</paper-item>
<paper-item>Art</paper-item>
</core-menu>
</paper-dropdown>
</paper-dropdown-holder>
My problem is deciphering The documentation to figure out how to automatically put the text of the currently-selected menu item into the paper-dropdown-holder.
My first attempt was to just use a standard paper-dropdown-menu, but I couldn't as easily style that like a paper-button. Is there any way to do this that's not (for lack of a better term) hacky? I'd love if the answer would keep to the Polymer philosophies.
Bonus challenge: How do I set default text like "choose section"?
One of awesome things of Polymer is it's open source... that said you could learn how to implement new element based on already existing elements....
If you have a look at paper-dropdown-menu source you could easily make something like it but with paper-button as a "control".
So
The new element should extend core-dropdown-base not
paper-button.
To make that element logically working you could do that with
some help of paper-dropdown-menu by binding (core-overlay-open,
core-activate, core-select) events to the according handlers.
(the actual binding happens in core-dropdown-base in dropdown
getter which called inside attached event listener.
To put them together:
<polymer-element name="paper-dropdown-holder" extends="core-dropdown-base" relative>
<template>
<div>
<paper-button raised on-tap="{{toggle}}">{{selectedItemLabel || label}}</paper-button>
<content></content>
</div>
</template>
<script>
Polymer('paper-dropdown-holder', {
publish: {
label: 'Select an item',
},
selectedItemLabel: '',
overlayListeners: {
'core-overlay-open': 'openAction',
'core-activate': 'activateAction',
'core-select': 'selectAction'
},
activateAction: function(e) {
this.opened = false;
},
selectAction: function(e) {
var detail = e.detail;
if (detail.isSelected) {
this.selectedItemLabel = detail.item.label || detail.item.textContent;
} else {
this.selectedItemLabel = '';
}
}
});
</script>
</polymer-element>
Demo.

Iterating through polymer content insertion points

What I'd like is for the following html:
<father name = "John">
<son name = "Bob">likes lollipops</son>
<son name = "David">likes computers</son>
</father>
to generate:
John has two sons, Bob and David:
Bob: likes lollipops
David: likes computers
Now, assume I've correctly written the "son" polymer tag, and it renders a block div with "Bob: likes lolipops" as the contents. this I can get working easily, so that I have something like:
John
Bob: likes lolipops
David: likes computers
However, to get that top line, I'm really not sure what the correct approach is, basically I'd like something like this:
<polymer-element name = "father" attributes = "name">
<template>
<style>...
</style>
<div layout vertical>
{{name}} has ???{count}??? sons, ???{{ iterate son nodes, print out name attribute for each }}???<br/>
<!-- I dont know how ot access JS here, so not sure how to turn all child nodes into a children array -->
<content select = "son"></content>
</div>
</template>
<script>
Polymer({});
</script>
</polymer-element>
There are probably a few ways of doing this, but here's one approach. (Full version on JSBin).
<polymer-element name="son-element" attributes="name" noscript>
<template>
<p>{{name}}: <content></content></p>
</template>
</polymer-element>
<polymer-element name="father-element" attributes="name">
<template>
<p>{{name}} has {{count}} sons, {{sons}}:</p>
<p><content id="content"></content></p>
</template>
<script>
Polymer({
count: 0,
sons: '',
domReady: function() {
var names = [].map.call(this.children, function(sonElement) {
return sonElement.name;
});
this.count = names.length;
this.sons = names.join(' and ');
}
});
</script>
</polymer-element>
<father-element name="John">
<son-element name="Bob">likes lollipops</son-element>
<son-element name="David">likes computers</son-element>
</father-element>
The key piece is hooking into the domReady lifecycle method of <father-element>, and inspecting its, erm, children. Since we know they'll all be <son-element>s, we just blindly look for their name attributes and map them to an array, but if you wanted you could take some steps to only query for the <son-element>s.
(Oh, and Polymer elements all need to have a - in their names, so you'd need to go with <father-element> (or the like) instead of <father>.)
This is my solution, it is based on Jeff Posnick's solution but with Scott Miles suggestion to listen for add- remove- events.
<polymer-element name="baby-element" attributes="name">
<template>
<p>{{name}}: <content></content> <input type="button" value="Kill Baby" on-click="{{killBaby}}"/></p>
</template>
<script>
Polymer("baby-element", {
attached: function(){
this.fire('baby-added');
},
killBaby: function(){
this.fire('baby-removed');
// this.remove();
},
detached: function() {
this.fire('baby-removed');
}
});
</script>
</polymer-element>
<polymer-element name="parent-element" attributes="name">
<template>
<p>{{name}} has {{count}} babys, {{babys}}:</p>
<p><content id="content"></content></p>
</template>
<script>
Polymer({
count: 0,
babys: '',
domReady: function() {
this.recalcBabys();
this.addEventListener('baby-added', this.babyAdded);
this.addEventListener('baby-removed', this.babyRemoved);
},
babyRemoved: function(e) {
e.target.remove();
this.recalcBabys();
},
babyAdded: function(e) {
this.recalcBabys();
},
recalcBabys: function(){
var names = [].map.call(this.children, function(babyElement) {
return babyElement.name;
});
this.count = names.length;
this.babys = names.join(' and ');
}
});
</script>
</polymer-element>
<h1>It's aparent baby thing:</h1>
<input type=button value="make baby" id="makeBaby"></input>
<input type=input placeholder="baby name" id="babyName"></input>
<input type=input placeholder="baby info" id="babyInfo"></input>
<parent-element id="parent" name="Slim Sim">
<baby-element name="Curie">has X</baby-element>
<baby-element name="Korbut">volts like no other!</baby-element>
<baby-element name="Pavlov">has dogs!</baby-element>
<baby-element name="Schrodinger">... maybe has a cat?</baby-element>
</parent-element>
<script>
document.getElementById('makeBaby').addEventListener('click', function(){
var name = document.getElementById('babyName');
var info = document.getElementById('babyInfo');
var parent = document.getElementById('parent');
var baby = document.createElement("baby-element");
var inner = document.createTextNode(info.value);
baby.appendChild(inner);
baby.setAttribute("name",name.value);
parent.appendChild(baby);
});
</script>
I did not manage to get the parent-element to recalculateBabys if the baby is removed from outside, with for instance document.getElementsByTagName('baby-element')[0].remove().
I would have liked to (on the baby-element) only have the attached and detached methods fire the baby-added and baby-removed events, and the killBaby-funktion to only do 'this.remove()'.
But I could never get the Parent to hear all those events...
Please feel free to scrutinize this code and tell me any errors, I am kind of new to Polymer, but I still hop I can contribute!