I have the following markup in my html:
<form is="iron-form" login-form>
<paper-input label="Email" type="email" name="email"></paper-input>
<paper-input label="Password" type="password" name="password"></paper-input>
<paper-button class="self-end btn-primary" raised login-btn>Login</paper-button>
</form>
In chrome, the form is never upgraded to an iron-form, but it works fine in firefox. However, I can use: document.createElement('form', 'iron-form'); to create an iron-form that is properly upgraded.
This is driving me crazy. Any ideas? Thanks
I'm not sure why the iron-input should work any differently. Are you sure the iron-input is working perfectly as a Polymer element when you create it in the template? (For example, does it have the utility functions like debounce?) I ask because it looks like a standard input.
Looking at the Meteor code, it doesn't look like any type-extension elements should work. As far as I can tell, it looks like all tag creation goes through here:
https://github.com/meteor/meteor/blob/832e6fe44f3635cae060415d6150c0105f2bf0f6/packages/blaze/materializer.js#L99
To handle type-extension custom elements, I think this needs another branch that does something like:
} else if (tag.attrs && ('is' in tag.attrs)) {
// type-extension custom element
elem = document.createElement(tagName, tag.attrs[is]);
} else {
// normal elements
elem = document.createElement(tagName);
}
The two-arg createElement will only work if you have native custom element support or you have the polyfill installed, so Meteor might want to handle this another way.
Related
Using Polymer 1.0, I set up an iron-form to submit a simple contact form. The idea is to submit the form to a database table using PHP and then display a response from the PHP side into the browser without refreshing - typical AJAX. I'm getting hung up on the Polymer environment though - it seems like there should be a correct way to do this, but hours of searching and tinkering hasn't been fruitful.
I did start this project using the Polymer Starter Kit (lite), which uses a script (app.js) to add event listeners and such. So far I haven't broken that functionality, though all of the examples in documentation do NOT do it this way, so it makes things a little more complicated since I'm still getting used to Polymer in general.
Here's what I've got so far. Thanks so much for any advice you can offer.
index.html
<!-- this is where the output should be displayed -->
<div id="output"></div>
<!-- this is the web form -->
<form is="iron-form" id="contactus-form" method="post" action="/">
<input type="hidden" name="action" value="contactus-form">
<paper-input id="contactus-field-Name" name="Name" label="Name" value="test"></paper-input>
<paper-button onclick="submitHandler(event)">Send</paper-button>
</form>
...
<script src="script/app.js"></script>
<script>
function submitHandler(event) {
Polymer.dom(event).localTarget.parentElement.submit();
}
</script>
app.js
(function(document) {
'use strict';
addEventListener('iron-form-submit', function(e) {
// this works and displays the POSTed values in the browser
document.querySelector('#output').innerHTML = JSON.stringify(e.detail);
// I'm looking for a way to first submit this data through PHP and
// display the output of that process in the #output div rather than the
// raw form input itself.
}
})(document);
FAILED METHOD 1
I tried adding an iron-ajax element into index.html and referencing it from app.js as shown below. Unfortunately, when it tries to add the event listener, the entire app crashes. It seems strange because there are many other pieces in app.js which add event listeners in the same way.
index.html
<iron-ajax id="contactus-output" url="/form/contact.php" params="" handle-as="json"></iron-ajax>
<!-- same form as before goes here -->
app.js
var coutput = document.querySelector('#contactus-output');
coutput.addEventListener('response', function() {
// nothing fancy here yet, just trying to see if I can do this
document.querySelector('#output').innerHTML = 'hello world';
}
FAILED METHOD 2
I found This Answer on SO and decided to try the iron-form-response event. The output I receive now is [object HTMLElement], which is at least something, although I'm not sure if it is actually working or not.
Everything else staying the same, I changed the target of my form to point to my php script and then replaced what I had in app.js with the following:
app.js
addEventListener('iron-form-response', function(e) {
document.querySelector('#output').innerHTML = e.detail;
});
Am I getting any closer?
NOT GIVING UP
Using my second failed method above, the iron-form appears to be making a request, because when I listen for the 'iron-form-response' event, it does fire.
However, the only thing that gets returned is [object HTMLElement] - no idea what to do with that. I tried spitting out some of its properties (as documented on developer.mozilla.org - .title, .properties, .style, etc) but they appear to be empty. Does iron-form really return an HTMLElement object or is this a mistake? I had figured it would return the results from the PHP script I'm submitting the form to just like a normal XMLHttpRequest. If iron-form somehow compresses this into an object, is there a way to pull it out again?
TL;DR
I think what this entire thing boils down to is this: HOW can I properly add an Event Listener (for iron-form-request) when my iron-form is in index.html and index.html is bootstrapped by app.js as happens by default in the Polymer 1.0 Starter Kit?
Further Simplified: How do I add event listeners properly to Polymer's shadow DOM when I'm NOT creating an element (just using it)?
BUG?
With the help of user2422321's wonderful answer below, the iron-request is being performed and a successful iron-request response is received. However, its "response" property returns NULL even though "succeeded" returns true, there were no errors, and the XHR resolved completely. Both "get" and "post" methods were tested with the same NULL result.
I see that there was a bug which matches these symptoms precisely logged in GitHub 10 days ago, though it hasn't seen much attention: Issue 83. This is unfortunate, but it appears to be a bug. I'm not convinced there will be any way to get this working until the element itself is repaired.
WHAT DOES IRON-REQUEST WANT TO SEE?!
As I explore this further, I see that even the XHR directly is returning "null" even though it has the responseURL correct and a statusText of "OK". I'm beginning to wonder if the actual PHP script I'm trying to run - which currently just outputs "Hello World" - is at fault.
Does iron-form-request expect a certain format or data type in the results? I tried adding header('Content-Type: text/plain'); to my PHP file, then I tried formatting it as a verified JSON string, but response is still null. Seems that nothing works.
Old school direct XMLHttpRequests work normally... is iron-form malforming something before the request even gets submitted?
I did set up a handler to catch iron-form-error but none are received. According to every single piece of information in the response, everything is perfect in the world. Just... null response. Over and over and over again... this is so incredibly frustrating.
SOLUTION! (sort of)
Okay, I got desperate enough that I started thumbing through the iron source code itself. It appears that iron-form is still somewhat glitchy at the moment and only returns content if the response is properly formatted json. In iron-request.html, it appears to allow the following types, but don't be fooled. I could only get json to work - I assume the rest will eventually fall into line.
json (application/json)
text (text/plain)
html (text/html)
xml (application/xml)
arraybuffer (application/octet-stream)
Therefore, for the time being, we need to format our response as JSON and include a DOCTYPE declaration to match.
In my case, this looks like so (thanks goes out to user2422321 for helping me so much):
index.php
<div id="output">{{myOutput}}</div>
<form is="iron-form" id="contactUsForm" method="get" action="/contactus.php" on-iron-form-response="_onResponseRetrieved">
<paper-input id="Name" name="Name" value="text" label="Name"></paper-input>
<paper-button id="contactSubmitButton" on-tap="_submitHandler">Submit</paper-button>
</form>
app.js
(function(document) {
...
app._onResponseRetrieved = function(e) {
this.myOutput = e.detail;
console.log(e);
};
app._submitHandler = function(e) {
this.$.contactUsForm.submit();
});
...
})(document);
Then finally, and this was the important last piece of the puzzle. I hadn't previously considered that the contents this file outputs would be very important since straight up XMLHttpRequests return whatever the file spits out.
contactus.php
<?php
// This is the line I added
header('Content-Type: application/json');
// Actual Code goes here
// Then make sure to wrap your final output in JSON
echo '{"test":"this is some test json to try"}';
With all those pieces in place, it works and e.detail.response contains the JSON response we echoed from contactus.php.
Not quite sure I understand what is it that doesn't work, but this is how I think it should be done "pure" Polymer way (by that I mean as little Javascript as possible).
<div id="output">{{myOutput}}</div>
<!-- this is the web form -->
<form is="iron-form" id="contactUsForm" method="post" action="/" on-iron-form-response="_onResponseRetrieved">
<input type="hidden" name="action" value="contactUsForm">
<paper-input id="contactus-field-Name" name="Name" label="Name" value="test"></paper-input>
<paper-button on-tap="_submitHandler">Send</paper-button>
</form>
_onResponseRetrieved: function(e)
{
//I'm not 100% sure what e.detail actually contain, but the value your looking for should be inside there somewhere
this.myOutput = e.detail;
}
_submitHandler: function(e)
{
//Note that I renamed the id of your form :)
this.$.contactUsForm.submit();
}
I've also seen recommendation that onclick should be on-tap so that it works properly on mobile devices, therefore I changed it.
The UI should now update as soon as you receive a response from the server!
-
EDIT:
Because you are using Polymer Starter Kit which is doing some of main logics inside the index.html some things are a bit different. In the Polymer documentation one is usually given examples where they show some piece of code inside an element, while the index.html does not look or function exactly as an element, which indeed can be confusing. In my own project I actually skipped all logics inside the index.html because I thought it seemed messy and complicated, but when looking back it's not all that weird (still not pretty in my opinion). I'm not sure about this, but the way index.html is setup might be the way to setup custom-elements if you want to separate the code (javascript) and the look (html/css).
So to get your code working:
In app.js you see this line:
var app = document.querySelector('#app');
You can think of the app variable as a custom-element.
In index.html you can see this line, which kinda says: "if you click on me I will call the method onDataRouteClick in the element app":
<a data-route="home" href="/" on-click="onDataRouteClick">
So, why will it call the method on the element app? That's because the line above is a child of: <template is="dom-bind" id="app"> (note the id has nothing to do with this, other than that we located it in Javascript by that id, so when I talk about the app object I'm talking about the one in Javascript).
Inside app.js we can then define what will happen when onDataRouteClick is called by doing the following:
app.onDataRouteClick = function() {
var drawerPanel = document.querySelector('#paperDrawerPanel');
if (drawerPanel.narrow) {
drawerPanel.closeDrawer();
}
};
I don't know why, but they keep using this line to find objects:
var drawerPanel = document.querySelector('#paperDrawerPanel');
But when you are in the scope of app you can actually use this instead, which I think is more Polymerish:
var drawerPanel = this.$.paperDrawerPanel;
-
Sorry if you knew all this already, now how do we get your code working?
Inside app.js you add this:
app._onResponseRetrieved = function(e)
{
//I'm not 100% sure what e.detail actually contain, but the value your looking for should be inside there somewhere
this.myOutput = e.detail;
console.log(e); //Check the console to see exactly where the data is
};
app._submitHandler = function(e)
{
//Note that I renamed the id of your form :)
//We are in the scope of 'app' therefore we can write this
this.$.contactUsForm.submit();
};
And in index.html you would have something similar to this (obviously it should be within the template element):
<div id="output">{{myOutput}}</div>
<!-- this is the web form -->
<form is="iron-form" id="contactUsForm" method="post" action="/" on-iron-form-response="_onResponseRetrieved">
<input type="hidden" name="action" value="contactUsForm">
<paper-input id="contactus-field-Name" name="Name" label="Name" value="test"></paper-input>
<paper-button on-tap="_submitHandler">Send</paper-button>
</form>
I am using Polymer 2 and I had a similar problem like this.
Here is my element file :
<template is="dom-bind">
<iron-ajax
auto
id="ajax"
url="test.php"
handle-as="json"
method="POST"
body='{"email":"ankita#gmail.com", "lastlogin":"Feb 21st 2016", "notifications":6}'
content-type = "application/json"
last-response="{{responseObject}}" >
</iron-ajax>
<login-element details="[[responseObject]]"></login-element>
</template>
And the login-element.html looks like this:
<dom-module id="login-element" >
<template>
<!--<form action="test1.php" method="post" enctype='application/json'>-->
<!--Name: <input type="text" name="name"><br>-->
<!--E-mail: <input type="text" name="email"><br>-->
<!--<input type="submit" onclick="submitForm()">-->
<!--</form>-->
<h2>{{details.email}}</h2>
</template>
<script>
Polymer({
is:"login-element",
properties:{
details:Object
}
});
</script>
And test.php
<?php
$data = json_decode(file_get_contents('php://input'), true);
echo json_encode($data);
exit;
I have a page with a FileUpload control rendered dynamically. At runtime, Asp generates the following input:
<input name="ctl00$ContentPlaceHolder1$ucPF$ucCustomField2$field2" id="field2"
type="file" Validators="[object HTMLSpanElement]"
cachedHoverStateItem="[object Object]"/>
In Google Chrome, the display seems to be spot on:
However, in IE8, not so much:
I know it's a small detail, but it still bothers me unreasonably. Any one of you would happen to know why the text is not vertically aligned and what can I do to fix it? Perhaps it's not a normal behaviour and I'm doing something wrong on my end?
I have tried adding the following CSS:
input[type="file"] {
line-height: 1ex;
}
But it didn't change anything.
File inputs are actually platform dependent and there is no standard way to style them... I've worked with them in the past and what most people tend to do is create an invisible file input and a separate text-input/button combi. The on-click of the button then triggers the on-click of the file input, and after the file input has a value it is copied to the text-input via Javascript.
Something like this (pseudo-code):
<input type="file" id="file" style="visibility:hidden" onchange="setFile(this.files[0])" />
<input type="text" id="filename">
<button onclick="document.getElementById('file').click()" />
With something like this in Javascript:
function setFile(file) {
var input = document.getElementById("filename");
input.value = file.name;
}
The code above asserts you're only supporting browsers which support the new (in progress draft) of the File API, there will certainly be ways to do this for older browsers as well...
Another approach (which works for older browsers) is described here
input[type="file"] {
line-height: 1ex;
}
Is this the line height of your text box? I thought ex indicated the height of the letter itself. Try adding the height of the actual box.
I want to rewrite the <input type="number"> element with Polymer so that i can <input is="number-input"> and style it in a way so that it looks and behaves the same on different browsers.
This is where I'm at now:
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="number-input" extends="input" attributes="value">
<script>
Polymer('number-input', {
valueChanged: function(){
console.log(this.value)
}
});
</script>
</polymer-element>
... and using it by <input is="number-input">, but it doesn't fire the valueChanged function.
What am I doin wrong?
Teltrik did a recent article on styling inputs with shadow dom that was pretty interesting: http://developer.telerik.com/featured/comprehensive-guide-styling-file-inputs/
In your case, you're doing everything correctly. The problem however, is that input already has a .value property. You're trying to override the native property which creates unpredictable behavior. The second issues is that Object.observe() cannot observe native properties on elements. For example, if you added the hidden attribute, hiddenChanged would never be called. Likewise for title and titleChanged.
I'm using EmberJS for my webapp and when I create a new record (set in edit mode), my first field (input text) has the autofocus="autofocus" parameter set. It works on Chrome the first time without problem, but not after.
The page loads once because it's an Ember app, and the views (record views) are being re-generated when I create a new record.
Any idea how to resolve this issue?
EDIT:
I have removed the autofocus property, and tried only to use Jquery focus() like in https://stackoverflow.com/a/14763643
App.FocusedTextField = Em.TextField.extend({
didInsertElement: function() {
this.$().focus();
}
});
Now, there is no focus even the first time. Also, if I tried replacing this.$().focus(); with this.$().hide();, then the input is hidden. this.$() in the console shows the right input as well, but focus() just does not work!
I would consider moving your input to a view or a component and then do something like this.$().focus(); in the didInsertElement function.
I came across the exact same issue with autofocus but the .focus() function did work for me. Here's how I coded it:
html:
<input type="text" id="idTextbox"/>
javascript:
$('#idTextbox').focus();
Thanks for spending time to read this
I have a form where is call a JS function to copy the html content of a DIV to a hidden form field so that I can submit this with the form. It works fine on desktop webkit broswers and also on mobile safari on iPad. However when I run the application in fullscreen mode (by saving a shortcut on home screen), this does not work.
Here's my code
JS function:
function update_script_in()//copies scripts and submits the form
{
$("#script_in").html($("#scriptContent").html());
$('#ResiForm').submit();
}
form submission:
<input type=submit value="Submit" onclick="update_script_in()">
Thanks for your help
This is quite old, but after googling around to solve the same issue for me, I have not found a solution. Looks like some weird behaviour from iPad (easily reproducible, no way to fix, at least that I found): the target input field gets changed indeed, but the posted value is the original one (???)
So just in case a workaround is useful to somebody, instead of applying the changes from the contenteditable div on form submit, I apply the changes whenever the div is changed (no on change event for contenteditable divs, so really it is done on blur event):
<div id="editor_inline_core_body" class="inputbox editor-inline" contenteditable>[initial value here]</div>
<input type="hidden" id="jform_core_body" name="jform[core_body]" value="[ initial value here]" />
<script>
jQuery('#editor_inline_core_body').blur(function() {
var value = jQuery('#editor_inline_core_body').html();
jQuery('#jform_core_body').val(value);
return true;
});
</script>
Less efficient, but at least it works. If you want a bit more of efficiency, you can check old and new values using also focus event, but at least I do not think it is a big deal or worth the added complexity.