【问题标题】:Fire javascript event when file starts to download - when response is received文件开始下载时触发​​ javascript 事件 - 收到响应时
【发布时间】:2023-04-11 08:17:02
【问题描述】:

目的是在服务器准备下载文件时显示等待微调器图标。在我的用例中,我正在生成一个大型报告,在调用浏览器的下载/另存为提示之前,服务器端需要一些时间。我可以向等待微调器显示没有问题,但找不到清除它的方法。

当前相关代码:

<h:commandButton id="generate" value="Generate Report" type="submit" 
    action="#{bean.generateReport()}" 
    onclick="#{rich:component('waitIcon')}.start();"/>

<a4j:status id="waitIcon">
     <f:facet name="start">
       <h:graphicImage value="/images/ai.gif" alt="ai" />
    </f:facet>
</a4j:status>

bean.generateReport() 是一个需要 1-10 秒服务器端的操作,然后返回下载响应。

这是使用 Richfaces a4j:status 指示器,因为它提供了有用的 API,例如 .start() 和 .stop() 但它也可以是任何 dom 元素并设置可见性。问题是我无法获得正确的事件来挂钩。我需要捕获类似 onresponsereceived 的内容...

我尝试过的解决方案:

使用a4j:commandButton 会提供oncomplete 事件,但按钮会生成AJAX 请求,无法开始下载。 (见h:command button oncomplete action

使用window.timeout 函数在组件上调用.stop()。这在功能层面上是可行的,但由于生成时间在 1-10 秒之间波动很大,这使得指标有点不反映现实。

有人对处理这个有什么好的想法吗?

【问题讨论】:

  • 您的问题标题令人困惑。您似乎对在文件下载完成后触发 JS 代码感兴趣。你能修改一下吗?
  • 我实际上有兴趣在文件下载开始时触发 JS 代码(浏览器收到响应)。我希望显示微调器的事件增量来自请求发送-> 响应接收。通过 onclick 事件可以轻松发送。收到...不是这样:)

标签: javascript html jsf download


【解决方案1】:

一种方法是返回到您有条件地呈现一段 JS 代码以启动实际下载的同一页面。

<h:form>
    ...
    <h:commandButton value="submit" action="#{bean.prepareFileForDownload}" />
    <h:outputScript rendered="#{bean.fileReadyForDownload}">
        // Do here your thing to indicate start of download.
        window.location = '#{bean.fileDownloadURL}';
    </h:outputScript>
</h:form>

另一种方法是定期检查 cookie。您只需要生成一个 URL 安全值作为某种下载令牌(System.currentTimeMillis() 完全适用于此)。

<h:form>
    ...
    <input type="hidden" name="token" value="#{bean.token}" />
    <h:commandButton value="submit" action="#{bean.downloadFile}" onclick="checkToken(this.form.token)" />
    <h:outputScript>
        function checkToken(token) {
            var pollDownloadStart = setInterval(function() {
                if (document.cookie.indexOf("download=" + token) > -1) {
                    document.cookie = "download=" + token + "; expires=" + new Date(0).toGMTString() + "; path=/";
                    clearInterval(pollDownloadStart);
                    // Do here your thing to indicate start of download.
                }
            }, 500);
         }
    </h:outputScript>
</h:form>

这个在downloadFile()

// Prepare download here.
// ...

// Once finished, set cookie and stream download to response.
Cookie cookie = new Cookie("download", token);
cookie.setPath("/");
response.addCookie(cookie);
// ...

【讨论】:

    【解决方案2】:

    简单的解决方案是将 setTimeout 设置为 1 秒以检查是否已收到响应。 setTimeout 将重复直到被清除。

    所以你可以这样做:

    var responseReceived, hTimer = setTimeout( function() {
        if( responseReceived ) {
            // code to stop/hide spinner here
            clearTimeout( hTimer );
        }
    }, 1000 );
    
    // responseReceived is set when the response is received
    

    或者,您需要的是编程术语中所谓的彗星。对于您的需要,Ajax 长轮询应该最适合您的需要。您基本上打开了对服务器的 ajax 请求(这是异步的),并且当服务器响应时,回调函数会执行您想要的任何操作。看看这些参考资料:

    【讨论】:

    • 了解responseReceived 何时才是真正的问题:) 彗星链接中的 iframe 建议看起来是最有希望的,但是我相信尝试通过以下方式启动下载时我会遇到类似的麻烦通过该 iframe 的 javascript/ajax。将证明它并回复......我希望有一个更直接的解决方案。
    • 啊,我误解了你关于 window.timeout 的观点。在这种情况下,彗星解决方案可能是您最好的选择
    【解决方案3】:

    如果我理解正确,您的用户会在 form 中填写一些数据,然后单击 submit 按钮将数据 POST 到服务器然后对其进行处理,并在一段时间后生成一个触发“另存为...”对话框窗口的响应。如果正确,解决方案是创建一个隐藏的 iframe,然后通过在form,最后挂钩 iframeonload 事件。

    【讨论】:

      猜你喜欢
      • 2014-08-30
      • 2019-04-17
      • 2010-09-23
      • 2012-05-05
      • 1970-01-01
      • 2010-12-04
      • 1970-01-01
      • 2012-12-16
      • 1970-01-01
      相关资源
      最近更新 更多