问题
I have an expensive form action that builds a zip file on the server and returns it to the browser.
<form action='/download' method='post'>
<input type='submit' value='download'/>
</form>
I want to block the page on click of the button so that the user doesn't repeatably hit the button.
However I want to unblock the page after the form returns.
How can trigger an event on successful completion of the form?
(I know I can trigger this by changing the form to be an ajax submission but then the save file dialog does not appear...)
Any suggestions?
Thanks
回答1:
One way you could handle this without using AJAX could be submitting the content of the form to an iframe
element. If you attach an onsubmit function to the form that disables further submissions and attach an onload function to the iframe, you should be able to disable the user from submitting the form multiple times.
Example HTML:
<form action="/download" method="post" target="downloadFrame" onsubmit="return downloadFile();">
<input type="submit" value="download" />
</form>
<iframe style="width: 0px; height: 0px;" scrolling="no" frameborder="0" border="0" name="downloadFrame" onload="downloadComplete();"></iframe>
Example Javascript:
var downloading = false;
function downloadFile() {
var isDownloading = downloading;
downloading = true;
return !isDownloading;
}
function downloadComplete() {
downloading = false;
}
回答2:
It appears no one has yet found a way to detect the post return in the browser itself, but there is another possibility using AJAX. It is a bit more involved though:
<script type="text/javascript">
$(function () {
$('#submitbtn').click (function () {
window.setTimeout (dldone, 100);
return true;
});
function dldone () {
$.get ("/downloadstatus?rand="+$('#rand').val (), function (data) {
if (data == 'done') {
// data generation finished, do something
} else {
window.setTimeout (dldone, 100);
}
});
}
});
</script>
<form action="/generatedata" method="post">
<input type="hidden" id="rand" value="[RANDOMVALUE]">
<input type="submit" id="submitbtn" value="Download Data">
</form>
On the server, you would have to do some inter-process-communication to signal when the data generation is done. Since I already have a database, I did it like this:
public function downloadstatusAction () {
if ($this->db->fetchOne ("SELECT rand FROM dlstatus WHERE rand = ?", (int) $_GET["rand"])) {
$db->delete ("dlstatus", array ("rand = ?" => (int) $_GET["rand"]));
print "done";
} else {
print "loading";
}
}
public function generatedataAction () {
// generate data
$this->db->insert ("dlstatus", array ("rand" => (int) $_POST["rand"]));
// output data
}
I am sure there are more elegant ways to do this, but you get the idea. This appears to work fine in all browsers I tested.
回答3:
I used this:
function generatePdfZipViaWS_ajax(theUrl) {
//=========================
// testé avec Chrome 37.0.2062.124 m, Firefox 32.0.3
// ça block avec IE9 à cause du xmlHttp.overrideMimeType
//=========================
var xmlHttp = new XMLHttpRequest();
var alert = document.getElementById("alertError");
block_UI();
var url = "undefined";
xmlHttp.open("GET", theUrl, true);
xmlHttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xmlHttp.overrideMimeType("application/octet-stream");
xmlHttp.responseType = "blob";
xmlHttp.onload = function(oEvent) {
if (xmlHttp.status == 200) {
deblock_UI();
// a mettre apres un certain temps: window.URL.revokeObjectURL(url);
} else {
alert.style.display = "block";
deblock_UI();
// console.log("Error " + xmlHttp.status + " occurred downloading your file.<br \/>");
}
};
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == xmlHttp.DONE) {
if (xmlHttp.status == 200) {
var contentDisposition = xmlHttp.getResponseHeader("Content-Disposition");
var type = xmlHttp.getResponseHeader("Content-Type");
var reponseType = xmlHttp.responseType;
var pos1 = contentDisposition.indexOf("archive");
var pos2 = contentDisposition.lastIndexOf(".zip") + 4;
var fileName = contentDisposition.substring(pos1, pos2);
if (fileName === null) {
fileName = "archivexxxxxxxxxxxxxx.zip";
}
console.log("fileName:" + fileName);
var blob = xmlHttp.response;
url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.style = "display: none";
a.href = url;
a.download = fileName;
a.type = type;
document.body.appendChild(a);
a.click();
//a.delete();
deblock_UI();
} else {
var msg =" Une erreur " + xmlHttp.status +" est apparue pendant que votre demande était traitée.\n"
msg = msg + "Merci de réessayer plus tard!";
alert.innerHTML = msg;
alert.style.display = "block";
deblock_UI();
console.log(msg);
}
}
};
xmlHttp.send();
}
回答4:
I don't have time to write a proper answer right now, but since nobody else has a good answer, I think a "Mutation Observer" would work... https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
来源:https://stackoverflow.com/questions/13529752/jquery-how-to-trigger-event-after-form-post-returns