jQuery如何在表单提交后触发事件?

6

我有一个昂贵的表单操作,它在服务器上构建一个zip文件并将其返回到浏览器。

<form action='/download' method='post'>

<input type='submit' value='download'/>

</form>

我希望在按钮点击时阻止页面,以防用户重复点击。

但是,我希望在表单返回后解除页面的阻止。

如何在表单成功提交时触发事件?

(我知道可以通过将表单更改为ajax提交来触发此操作,但是保存文件对话框则不会出现...)

有任何建议吗?

谢谢


你可以使用这个插件 http://www.malsup.com/jquery/form/#ajaxSubmit 并在 "success" 事件上执行任何你需要的操作。 - Mihai
尝试:http://jsfiddle.net/gRoberts/Ca9nB/ - 实际上,你只需要在提交按钮被点击后禁用它,以防止再次点击。当页面重新加载时,JavaScript 将被撤销,然后你就可以再次点击了。 - Gavin
@Gavin,问题在于页面不会重新加载,表单操作直接返回zip文件。 - Chris
@Jay Blanchard,问题就在于如何通过ajax处理文件下载。 - Chris
1
@JayBlanchard Chris正在使用表单来启动文件下载。使用Ajax只会创建zip文件,而不是下载。唯一的其他解决方案可能是使用Ajax创建zip文件,然后将该zip文件的路径作为响应返回,然后使用Javascript进行重定向? - Gavin
显示剩余3条评论
4个回答

5

一种不使用AJAX来处理这个问题的方法是将表单内容提交到一个iframe元素中。如果你将一个onsubmit函数附加到表单中以禁用进一步的提交并将一个onload函数附加到iframe中,那么你应该能够防止用户多次提交表单。

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>

示例Javascript:

var downloading = false;
function downloadFile() {
    var isDownloading = downloading;
    downloading = true;
    return !isDownloading;
}
function downloadComplete() {
    downloading = false;
}

1
我相信 onsubmit 事件是在提交时触发的,而不是在提交操作完成后触发的。 - Chris
@Chris 你说得对。这将防止进一步的提交发生。我忘记了当文件下载完成后页面不会重新加载。我很快会更新我的答案。 - Kyle
这确实可行,但远非理想。在某些错误条件下,我的操作将使用隐藏的iframe进行301重定向并显示消息,但这完全丢失了对用户来说看起来就像什么都没有发生。此外,我无法找到一种好的方式来绑定函数到iframe的加载事件上,而是需要像您所做的那样让iframe调用包含文档中的函数,这意味着污染全局命名空间。因此,我认为我将放弃这种方法,并将下载作为一个两步过程完成。感谢您的技巧,希望有人会发现它有用! - Chris
@Chris 是的,出于许多原因,这远非理想之选,但作为一个完整的一步过程,这是唯一的方法之一。如果您不想使用内联函数,您可以始终使用jQuery将load函数绑定到iframe上。另一种方法可能是使用表单上的target="_blank"打开提交到新窗口。 - Kyle

0

我使用了这个:

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();
}

IE和Safari var a = document.createElement('a'); var wasPageHide = 0; a.cssText= "display:none"; a.href = theUrl; document.body.appendChild(a); 如果(is_safari === true ){ var evObj = document.createEvent('MouseEvents'); evObj.initMouseEvent('click', true, true, window); a.dispatchEvent(evObj); }else{ a.click(); } 如果(window.addEventListener){ window.addEventListener('focus', deblock_UI, false); }else{ window.attachEvent('onfocus',deblock_UI); } - petro

0

目前似乎还没有人找到在浏览器本身中检测POST返回的方法,但是可以使用AJAX来实现另一种可能性。不过这需要更多的操作:

<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>

在服务器上,您需要进行一些进程间通信来表示数据生成完成的信号。由于我已经有了数据库,所以我是这样做的:
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
}

我相信有更优雅的方法来做到这一点,但你已经明白了。在我测试的所有浏览器中,这似乎都可以正常工作。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接