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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With