当文件开始下载时 - 在收到响应时触发javascript事件

时间:2013-06-14 18:35:43

标签: javascript html jsf download

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

当前相关代码:

<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-10secs服务器端的操作,然后吐出下载响应。

这是使用richfaces a4j:状态指示器,因为它提供了有用的API,如.start()和.stop(),但它也可以是任何dom元素和设置可见性。问题是我无法抓住正确的事件。我需要捕捉像onresponsereceived ......

我尝试过的解决方案:

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

使用window.timeout函数调用组件上的.stop()。这在功能层面上起作用,但由于生成时间在1-10秒之间相当剧烈地摆动,因此它使指示器不能反映现实。

任何人对处理这个有什么好主意吗?

3 个答案:

答案 0 :(得分: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);
// ...

答案 1 :(得分:0)

简单的解决方案是将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请求,并且回调函数在服务器响应时执行您想要的任何操作。看看这些参考文献:

答案 2 :(得分:0)

如果我理解正确,您的用户会以格式填充一些数据,然后点击提交按钮,将 POST 数据发送到服务器然后处理它,一段时间后它会生成一个响应,触发“另存为...”对话框窗口。如果这是正确的,解决方案是创建隐藏的 iframe ,然后通过在目标上设置目标属性,将服务器的响应重定向到 iframe 表单,最后挂钩 iframe onload 事件。