Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS function not triggered with PrimeFaces.monitorDownload

I'm working in file downloading with Primefaces 4.0. I just want to trigger a JS function when download completes, but seems not to work (tried in Firefox and Google Chrome). My test case looks similar to what's done in the PF docs:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">
<h:head />

<h:body>
    <script type="text/javascript">
        function startMessage() {
            alert("Download started!");
        }
        function finishMessage() {
            alert("Download finished!");
        }
    </script>
    <h:form>
        <p:commandButton value="Download" ajax="false"
            icon="ui-icon-arrowreturnthick-1-s"
            onclick="PrimeFaces.monitorDownload(startMessage, finishMessage)">
            <p:fileDownload value="#{bean.file}" />
        </p:commandButton>
    </h:form>
</h:body>
</html>
@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    public StreamedContent getFile() {
        return new DefaultStreamedContent(new ByteArrayInputStream(new byte[0]));
    }

}

The alert is triggered when download starts, but not when download finishes. Could anyone else give it a try?

like image 705
Xtreme Biker Avatar asked Dec 18 '13 16:12

Xtreme Biker


2 Answers

it's a bug.

The main bug is in FileDownloadActionListener of org.primefaces.component.filedownload package.

Line 65

externalContext.addResponseCookie(Constants.DOWNLOAD_COOKIE, "true", Collections.<String, Object>emptyMap());

The Constants.DOWNLOAD_COOKIE is "primefaces.download", and it's never sent with the response.

That would cause PrimeFaces.monitorDownload's Interval to never call the stop function, since the cookie is never written.

like image 93
Hatem Alimam Avatar answered Nov 07 '22 07:11

Hatem Alimam


I had the same problem and found it was related to the 'path' attribute of the cookie created.

My app context path has the form 'http://host/a/b/c', hence in the server the cookie is created with 'default' path as '/a/b/c', but in the browser I found the cookies retrieved during the JavaScript execution were only the ones with path '/a' (Chrome) or '/a/' (Firefox). So even when the 'primefaces.download' cookie was being created, the JavaScript in the client was not retrieving it for the application.

All I had to do was to 'override' the cookie creation before the response is sent (i.e. create a second cookie with correct path expected by the browser):

   ...
   FacesContext facesContext = FacesContext.getCurrentInstance();
   ExternalContext externalContext = facesContext.getExternalContext();
   Map<String, Object> map = new HashMap<String, Object>();
   map.put("path", "/a/");
   externalContext.addResponseCookie(Constants.DOWNLOAD_COOKIE, "true", map);
   ...

Also, I noticed the default implementation of PrimeFaces.monitorDownload() tries to 'clean' the 'primefaces.download' cookie by just setting its value to 'null', but since there is difference in how Chrome and Firefox handle cookies (appending a last '/' character to the current path in Firefox) I better did 'override' also the JS code to clean the cookie once the ending function is executed:

   ...    
   document.cookie = 'primefaces.download=; path=/a/; expires=Thu, 01 Jan 1970 00:00:00 UTC';
   ...

That way I make sure that in the next execution the cookie won't yet be there at all in the client until it again gets created in the server.

like image 38
Francisco Acevedo Avatar answered Nov 07 '22 06:11

Francisco Acevedo