Reputation: 1457
I have a form with a single file field:
<form id="myForm" action="/processFile" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile">
</form>
And I want to submit the form via AJAX (using jQuery on the client-side and Node.JS on the server side).
This is what I tried first on the client-side in jQuery (after looking at questions like this one Submit form via AJAX in jQuery):
submitButton.on('click', function(ev) {
$.ajax({
type: "GET",
url: $('#myForm').action
data: { form: $('#myForm').seralize() }
}).done(function(res) {
$('#targetDiv').html(res);
});
});
Sadly, this didn't work because the .seralize() method doesn't work for file inputs.
So I decided that actually posting the form was the best route because it handles the asynchronous messiness of uploading the file to the server. So I tried this:
submitButton.on('click', function(ev) {
$('#myForm').submit(function(err) {
$.ajax({
type: "GET",
url: $('#myForm').action
data: { form: $('#myForm').seralize() }
}).done(function(res) {
$('#targetDiv').html(res);
});
});
});
That is, (1) actually submitting the form, and then (2) making my ajax call in the callback of the form submission.
Sadly, this also doesn't work because submitting the form expects the entire page to reload based on the response from "/processFile".
What I want is (1) to submit the file input as simply as possible through AJAX, and (2) use the response of the URL to inject some partial HTML. It seems like you could hack around this using some iFrame trickery (like this http://www.jainaewen.com/files/javascript/jquery/iframe-post-form.html) but is there a cleaner way that I'm not seeing?
Upvotes: 3
Views: 4013
Reputation: 1457
I ended up just using the iframe trickery via the plugin here: http://www.jainaewen.com/files/javascript/jquery/iframe-post-form.html
Here's what my code looks like:
The form:
<form id="myForm" action="/processFile" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile">
<input type="submit" id="mySubmitButton" style="display: none;">
</form>
...
<button id="continueButton">Continue</button>
Note that for uninteresting reasons I wanted a button that had to reside OUTSIDE the form to do the submitting.
The JS:
$('#continueButton').on('click', function(ev) {
// I click the hidden submit inside the form
$('#mySubmitButton').click();
});
$('#myForm').iframePostForm ({
json : false // my server response is straight HTML
, post : function() {
// initiation of waiting sequence
return true; // returning false aborts the submit
}
, complete : function(res) {
$('#targetDiv').html(res); // I stick the response in the target div
}
});
One thing that tripped me up is that the way this plugin is implemented, just calling
$('#myForm').submit();
Inside the onclick of the continueButton does NOT work. Firing form.submit() directly must circumvent jQuery's event handling in some bad way. So my workaround (as you can see) was to put an invisible form submission button inside the form and have my external button click on that. This seemed to play nicely with both jQuery and the plugin.
Hope this helps someone! I didn't find the doc on the plugin's website to be as friendly as I had hoped.
Upvotes: 1
Reputation: 1038710
If the browser you are using supports HTML5 you could use the new XMLHttpRequest
object which allows you to achieve that. Your code might look like that:
submitButton.on('click', function(ev) {
var form = $('form')[0];
var fd = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// handle success case
}
};
xhr.send(fd);
return false;
});
If your client browsers do not yet support HTML5 or you don't have control over them you could use a file upload plugin such as Uploadify
, jQuery.form
, FineUploader
, ... which will test the capabilities of the browser and use the most appropriate technique.
Upvotes: 2