【问题标题】:jQuery how to trigger event after form post returns?jQuery如何在表单发布返回后触发事件?
【发布时间】:2012-11-11 20:35:43
【问题描述】:

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

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

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

</form>

我想在点击按钮时阻止页面,这样用户就不会重复点击按钮。

但是我想在表单返回后取消阻止页面。

成功完成表单后如何触发事件?

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

有什么建议吗?

谢谢

【问题讨论】:

  • 你可以使用这个插件malsup.com/jquery/form/#ajaxSubmit 并在“成功”事件中做任何你需要的事情
  • 可以在jQuery Ajax函数的回调中触发任意一组函数。
  • 试试:jsfiddle.net/gRoberts/Ca9nB - 真的,您需要做的就是在单击提交按钮后禁用它,以防止再次单击它。当页面重新加载时,javascript将被撤消,您可以再次点击。
  • @Gavin,问题是页面没有重新加载,表单动作直接返回zip文件。
  • @JayBlanchard Chris 正在使用该表单来启动文件下载。使用 Ajax 将只创建 zip 文件而不是下载。唯一的其他解决方案可能是使用 Ajax 创建 zip,然后返回该 zip 文件的路径作为响应,然后使用 Javascript 重定向?

标签: javascript jquery html unobtrusive-javascript


【解决方案1】:

您可以在不使用 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;
}

【讨论】:

  • 我相信 onsubmit 是在提交时触发的,而不是在提交操作完成时触发的。
  • @Chris 你是对的。这将处理进一步的提交。我忘记了当文件下载发生时页面不会重新加载。我会尽快更新我的答案。
  • 这确实有效,但远非理想,在某些错误情况下,我的操作将使用隐藏的 iframe 执行带有消息的 301 重定向,这完全丢失了,用户看起来好像什么也没发生。此外,我看不到将函数绑定到 iframe 的加载事件的好方法,而是像您所做的那样,我需要 iframe 来调用包含文档中的函数,这意味着污染全局命名空间。所以我想我会放弃这种方法,将下载作为一个 2 步过程进行。感谢您的破解,希望有人会发现它有用!
  • @Chris 是的,由于多种原因,这远非理想,但它是作为完整的 1 步过程完成的唯一方法之一。如果你不想使用内联函数,你可以随时使用 jQuery 来bind 加载函数到 iframe。另一种方法可能是在表单上使用target="_blank" 将提交打开到新窗口。
【解决方案2】:

似乎还没有人找到一种方法来检测浏览器本身的 post return,但是使用 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
}

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

【讨论】:

    【解决方案3】:

    我用过这个:

    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 et Safari var a = document.createElement('a'); var wasPageHide = 0; a.cssText="显示:无"; a.href = theUrl; document.body.appendChild(a); if (is_safari === true ){ var evObj = document.createEvent('MouseEvents'); evObj.initMouseEvent('click', true, true, window); a.dispatchEvent(evObj); }else{ a.click(); } if(window.addEventListener){ window.addEventListener('focus', deblock_UI, false); }else{ window.attachEvent('onfocus',deblock_UI); }
    【解决方案4】:

    我现在没有时间写一个正确的答案,但是由于没有其他人有一个好的答案,我认为“突变观察者”会起作用...https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-28
      • 2011-10-09
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多