Reputation: 96947
I use jQuery (v1.7.2) to submit()
a form via POST
. This calls a Python cgi-bin script to do some work that can take about ten seconds or so to complete. Once complete, the Python script instructs the browser to download data, e.g.:
print "Content-Type: text/plain"
print "Content-Disposition: attachment; filename=" + some_filename
print "Content-Description: File to download\n"
print some_stuff
The script works fine, but the browser UI is tied up while waiting for the Python script to do its job. The end user can't do anything.
How do I submit a form asynchronously, so that the user can keep interacting with the UI while the Python script does its work?
Failing that, how does one set up an activity indicator on form submission and form completion?
For instance, I tried overloading the submit()
function handler, but the following approach did not work for me:
$('#my_form').submit(function(e) {
$.ajax({
type: 'POST',
url: $(this).attr("action"),
data: $(this).serializeArray(),
beforeSend: function() {
/* show an activity indicator div in the browser window */
},
complete: function() {
/* hide activity indicator div */
}
});
});
When I submit the form, the beforeSend
and complete
routines are executed instantaneously and so I am unable to use this approach to give visual cues that the browser is tied up. Are there alternatives methods that work?
Upvotes: 0
Views: 491
Reputation: 5571
If you don't set: e.preventDefault();
your form will submit to the server without $.ajax().
Try with this:
$(function() {
$('#my_form').submit(function(e) {
$.ajax({
type: 'POST',
url: $(this).attr("action"),
data: $(this).serializeArray(),
dataType: "json" // Your server can response html, json, xml format.
beforeSend: function() {
$("#indicator").show();
},
success: function() {
$("#indicator").hide();
}
});
e.preventDefault(); // To stop the default form submission.
});
});
Python response:
print "Content-Type: text/plain"
print "Content-Disposition: attachment; filename=" + some_filename
print "Content-Description: File to download\n"
print some_stuff
However, according to the response from your server, you are trying to download a file. For this scenario, where you attempt to download a file, you must use a hidden iframe, because $.ajax(); will not work successfully.
Updated:
Possible Solution Using Hidden Iframe and jQuery:
To achieve simulate the effect of sending information via $.ajax();
, you can use a hidden iframe. Therefore, in your form, set the target property of the form: <form target="iframeName"></form>
.
Within the form, you add the following:
<iframe id="ifrHidden" hidden="hidden" name="ifrHidden"></iframe>
Thus, it is no longer necessary to use $.ajax();
To simulate the function of beforeSend of $.ajax();
you can try something like this:
$("#my_form").on("submit", function () {
$("#indicator").removeClass("hide"); // To show the indicator remove the hide css class.
});
Then, when the hidden iframe changes... Simulating the success function of $.ajax();
$("#ifrHidden").on("load", function () {
$("#indicator").addClass("hide"); // To hide again the indicator.
$("#info").fadeIn(); // Show information after the request.
});
Something like this:
$(function() {
$("#my_form").on("submit", function() {
$("#indicator").removeClass("hide");
});
$("#ifrHidden").on("load", function() {
$("#indicator").addClass("hide");
$("#info").fadeIn();
});
});
form {
font-family: Arial, sans-serif;
}
#indicator {
background: url(http://dfjb.webcindario.com/libreria/imagenes/ajax-loader.gif) no-repeat center center;
display: block;
height: 16px;
width: 16px;
}
.hide {
display: none !important;
}
#info {
background-color: #90EFA9;
border: solid 1px #469C70;
color: #196F30;
display: none;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form id="my_form" method="post" name="my_form" target="ifrHidden">
<div>File name:
<br />
<input name="txtFileName" type="text" value="" />
</div>
<div>Field2:
<br />
<input name="txtField2" type="text" value="" />
</div>
<button type="submit">Send</button>
<iframe id="ifrHidden" hidden="hidden" name="ifrHidden"></iframe> <span id="indicator" class="hide"></span>
<div id="info">You have sent the information...</div>
</form>
Don't forget to add the action
property to your form.
We have limitations to test over iframes in this site, but you can see the live demo in this link:
Upvotes: 2