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.