how to access input element in a polymer web-component - javascript

I've managed to setup a simple registration form with Polymer:
<polymer-element name="app-registration">
<template>
<style>
...
</style>
<section>
<paper-input class="username" .... ></paper-input>
<paper-input class="password" .... ></paper-input>
<paper-button label="Submit" on-tap="{{handleSubmit}}"></paper-button>
</section>
</template>
<script>
Polymer({
handleSubmit: function (event, detail, sender) {
alert(this.querySelector('.username').value);
}
});
</script>
</polymer-element>
It works fine, however, within the handleSubmit callback I'm not able to query the values from the other input fields. Whatever I query paper-input or by classname I receive null. Any suggestion how to do this ?

Those elements are in your shadow dom, so you need this.shadowRoot. this.querySelector() will give you light dom nodes.
this.shadowRoot.querySelector('.username').value
Better yet, would be to add an id:
<section id="container">
<paper-input class="username" .... ></paper-input>
...
</section>
and use node finding: this.$.container.querySelector('.username').value.

Not sure if it was already available in 0.5, but in 1.0 you can do
this.$$(selector)
your example:
this.$$('.username').value
-> same but shorter, and works on dynamically created nodes
https://www.polymer-project.org/1.0/docs/devguide/local-dom.html#work-with-local-dom

Related

Meteor Blaze tab key event

This Meteor code does not print to console the event.which so as to use tab key event when tabbing out of an editable div.
Why editable div? Because I can style part of the string which is not allowed in input element.
BTW: Where do I find a list of the events types for Meteor Blaze. There site only lists a very limited events. Other DOM events are available as well, but...
I tried some blur and onblur for no avail.
How can I fire a tab key event on an editable div? Thanks
//client/main.js template evnet
'onblur #vin'(e){
console.log(e.which) //prints nothing
let vin = e.target.value
}
<div class="body">
<div id="vin" class="editable" contenteditable="true">{{vehicle.vin_a}}<span id="vinb">{{vehicle.vin_b}}</span><span id="vin4">{{vehicle.vin4}}</span></div>
<input type="text" placeholder="make, modle, date">
</div>
It works for me!
Here is a minimal, reproducible example:
main.html:
<head>
<title>b</title>
</head>
<body>
{{> info}}
</body>
<template name="info">
<div id="vin" class="editable" contenteditable="true">
Edit me
</div>
</template>
main.js:
import { Template } from 'meteor/templating';
import './main.html';
Template.info.events({
'blur #vin'(event, instance) {
console.log('blur!', event);
}
});
Maybe you defined the event on the wrong template?

Polymer 1.0 add other polymer elements inside

Hello what is the difference of doing adding a child polymer element like this:
<dom-module id="app-element">
<template>
<h1>Hello</h1>
<test-element></test-element>
</template>
<script>
Polymer({
is: "app-element"
});
</script>
</dom-module>
<app-element></app-element>
This works just fine.
The effect of adding html code (including other polymer elements) inside the app-element tag
<app-element>some html here</app-element>
like this:
<dom-module id="app-element">
<template>
<h1>Hello</h1>
</template>
<script>
Polymer({
is: "app-element"
});
</script>
</dom-module>
<app-element>
<test-element></test-element>
</app-element>
This ignores the test-element code. So in which cases can I add html code inside a polymer element? When will it be ignored? What would be the case where you want to add polymer elements inside other polymer elements inside the html code like this:
<app-element>
<test-element></test-element>
</app-element>
?? Thank you
In your first case you are using local dom, in the second light dom.
In local dom, the custom element that contains it is responsible for the content (in this case app-element). So the creator of the custom element decides the content of the local dom. In contrast, using light dom provides the user of the custom element with the option to specify the content. The creator of the custom element can specify where the light dom should go inside the custom element using the <content></content> tag. So to make your second example work you would need something like this:
<dom-module id="app-element">
<template>
<h1>Hello</h1>
<content></content>
</template>
<script>
Polymer({
is: "app-element"
});
</script>
</dom-module>
<app-element>
<test-element></test-element>
</app-element>
An example use case for light dom is the paper-dialog. Using light dom, the user of the dialog can decide the content of the dialog. For example, the specific buttons to use, the main content of the dialog, etc.
Have a look at this page in the documentation for more information on local and light dom.

Polymer 1.0 can't access elements within nested <template> element

I am using Polymer 1.0 and I am building a small accordion example. I have data binding to the accordion text fine, I just want to change the icon of the accordion when I click it.
Below is my code
<dom-module id="ab-accordion">
<template>
<iron-ajax
auto
handle-as="json"
on-response="handleResponse"
debounce-duration="300"
id="ajaxreq"></iron-ajax>
<template is="dom-repeat" id="accordion" items="{{items}}" as="item">
<div class="accordion" on-click="toggleParentAcc">
<div id="accordion_header" class="accordion__header is-collapsed">
<i class="icon icon--chevron-down"></i>
<span>{{item.name}}</span>
</div>
<div id="standard_accordion_body" class="accordion__body can-collapse">
<div class="accordion__content">
<content id="content"></content>
</div>
</div>
</div>
</template>
</template>
<script>
Polymer({
is: "ab-accordion",
//Properties for the Element
properties: {
accordian: Object,
childaccordions: Object,
// Param passed in from the element - Set if the accordion is open by default.
open: String,
data: String,
reqUrl: {
type: String,
value: "https://example.com/service.aspx"
},
},
ready: function () {
this.items = [];
},
attached: function () {
// Run once the element is attached to the DOM.
},
toggleParentAcc: function (event) { // Toggle the classes of the accordions
//This is where I want to toggle the class
this.$.accordion_header.classList.toggle('is-collapsed');
if (typeof event !== 'undefined') {
event.stopPropagation(); // Stop the click from going up to the parent.
}
},
handleResponse: function (e) {
this.items = e.detail.response.sports;
}
});
</script>
</dom-module>
Basically inside the toggleParentAcc function I want to toggle the class of the div with ID accordion_header. But I just get undefined or null.
I have tried the following two lines:
this.$.accordion_header // #1
this.$$('#accordion_header') // #2
How I access that element inside the dom-repeat?
UPDATE: I can't even access the elements within the when inside the attached function.
attached: function(){
this.$.accordion_header // This is null?!
this.$$('#accordion_header'); // this is also null!
}
https://www.polymer-project.org/1.0/docs/devguide/local-dom.html#node-finding
Note: Nodes created dynamically using data binding (including those in dom-repeat and dom-if templates) are not added to the this.$ hash. The hash includes only statically created local DOM nodes (that is, the nodes defined in the element’s outermost template).
I think it would be better if you'd use Polymer.dom(this.root) instead. Also I'd advice you to not use static IDs in dom-repeat as they are meant to be unique. Use classes instead.
Looks like you might be encountering Event Retargeting which happens when events "bubble" their way up the DOM tree. Read this documentation to learn more.
When I encountered this, I solved it by using something like:
var bar = Polymer.dom(event).path[2].getAttribute('data-foo');
inside my Polymer() function.
To figure it out in your case, you should go to the console and search the DOM tree / event log to locate your target. If you have trouble locating the correct area of the console, post a comment and I might be able to help further.
I eventually figured out a way of doing this without having to select elements in the nested template.
<template id="accord_template" is="dom-repeat" items="{{items}}" as="item">
<ab-accordion-row id="[[item.id]]" name="[[item.name]]" open="[[item.open]]">
</ab-accordion-row>
</template>
ab-accordion is another element, I just feed it the data and I can then change the classes based on the params.
<div id="accordion" class="accordion" on-click="toggleAccordion">
<div class$="{{getClassAccordionHeader(open)}}">
<i class="icon icon--chevron-down"></i>
<span>{{name}}</span>
</div>
<div id="standard_accordion_body" class$="{{getClassAccordionChild(open)}}">
<div class="accordion__content">
<content></content>
</div>
</div>
</div>
try with this.
toggleParentAcc: function (event) { // Toggle the classes of the accordions
//This is where I want to toggle the class
var header = event.target.parentElement;
Polymer.dom(header).classList.toggle('is-collapsed');
// rest of your code
}

How to use Paper-Dialog in Polymer 1.0?

I think this post relates to Polymer 0.5 and seems not to work in Polymer 1.0. For a beginner like me, I see no clear implementation; just the actual function code and not a "How to". Here is my simple setup that does not work (assume I have imported all elements):
<dom-element id="my-app">
<template>
<paper-button raised id="toggleDialog"></paper-button>
<paper-dialog entry-animation="scale-up-animation"
exit-animation="fade-out-animation" onclick="{{toggleDialog}}">
<h2>Header</h2>
<div>Dialog body</div>
</paper-dialog>
</template>
<script>
Polymer({
is: "my-app",
properties: {
type: String,
observer: "" // not important for this example so it's empty.
},
// should I put the function here?
toggleDialog: function() {
this.$.dialog.toggle();
}
});
</script>
</dom-element>
I hope I am not doing something wrong.
Replace:
this.$.dialog.toggle();
with:
this.$.toggleDialog.toggle();
because:
The string after the cash sign $ needs to match the id.
And, finally:
Move the id="toggleDialog" attribute from the <paper-button> tag to the <paper-dialog> tag. Because you want to target the <paper-dialog> element with the .toggle() method. Not the <paper-button> itself.

Polymer 1.0 - Issue with displaying values inside template is="dom-repeat"

While migrating to Polymer 1.0 from 0.5 I have come across an interesting thing. Thought it might help others having similar problem.
I have an element where I am using <template is="dom-repeat" items="{{customers}}">...</template>. The problem I am facing is I have to place every single property binding inside a HTML element. The code below what I intended to write:
<template is="dom-repeat" items="{{customers}}">
<div>
{{item.name}}<br />
{{item.addr}}, {{item.addr2}}<br />
{{item.phone}}
</div>
</template>
But it is only displaying the value for {{item.name}}. The reason is other property bindings are not wrapped within separate HTML tags, they are not displaying at all!
I tried the following but didn't work either:
<template is="dom-repeat" items="{{customers}}">
<div>
<p>{{item.name}}</p>
<span>{{item.addr}} {{item.addr2}}</span>
</div>
</template>
Means, I put {{item.name}} inside a <p>...</p> tag and placed {{item.addr}} and {{item.addr2}} inside a single <span>...</span> tag.
Then I went on and put every single property binding wrapped by their own HTML tags like the following:
<template is="dom-repeat" items="{{customers}}">
<div>
<p>{{item.name}}</p>
<span style="display:block">{{item.addr}}, <span>{{item.addr2}}</span></span>
<span style="display:block;">{{item.phone}}</span>
</div>
</template>
and it works!!
I truly have no idea whether it is a bug of 1.0 or there is something I am doing wrong! If anybody knows the answer please help.
Thanks in advance
You're not doing anything wrong. With the introduction of Polymer 0.9 (and later 1.0) data-binding to the content of text nodes only works if you wrap everything into its own element.
See the Polymer documentation:
The binding annotation must currently span the entire content of the tag
So you have to remove all whitespace and other characters for it to work.
Example from the documentation:
<!-- this works -->
<template>
First: <span>{{first}}</span><br>
Last: <span>{{last}}</span>
</template>
<!-- Not currently supported! -->
<div>First: {{first}}</div>
<div>Last: {{last}}</div>
<!-- Not currently supported! -->
<div>
{{title}}
</div>
Edit
As of Polymer 1.2, the issue described in the question is no longer problematic / erroneous. Compound bindings now work, see release notes on the Polymer blog.
Just a heads up, for element attributes though you can use something like a helper function for string concatenation. Here's an example.
<my-foo fullname="{{computeFullName(firstname, lastname)}}">
Hi, my name is <span>{{firstname}}</span>.
</my-foo>
...
computeFullName: function(first, last) {
return first + ' ' + last;
}
And here's the link: https://www.polymer-project.org/1.0/docs/migration.html#data-binding
EDIT:
For node content as well, string concatenation can be done using computed properties (I call them helper functions). Here's an example,
<dom-module id="x-custom">
<template>
My name is <span>{{fullName}}</span>
</template>
</dom-module>
<script>
Polymer({
is: 'x-custom',
properties: {
first: String,
last: String,
fullName: {
type: String,
// when `first` or `last` changes `computeFullName` is called once
// (asynchronously) and the value it returns is stored as `fullName`
computed: 'computeFullName(first, last)'
}
},
computeFullName: function(first, last) {
return first + ' ' + last;
}
...
});
</script>
With Polymer 1.2 you example code will actually work. Binding annotations no longer need to span the entire tag.
Example:
<div>first name: [[name.first]] last name: [[name.last]]</div>
https://blog.polymer-project.org/releases/2015/11/02/release-1.2.0/
You'll want to use a computed property to combine values. Search for them on this page https://www.polymer-project.org/1.0/docs/devguide/properties.html

Categories

Resources