Board index JavaServer Faces General p:commandButton Call a javascript function if ajax=false

p:commandButton Call a javascript function if ajax=false

Components, Ajax Framework, Utilities and More.


Posts: 5
Hi everybody,

I have a commandButton which is calling a java method to generate an excel file, my question is : is it possible to call a javascript function once the file has been generated ?

Here is the code I use in the jsp :


      <p:commandButton id="extractionDataRegional" 
         actionListener="#{exportController.doExport}" ajax="false"
         oncomplete="myJavascriptFunction()"
         value="Do export" update="messages"  />


and the java method generating the excel file :


   public static void doExport() throws IOException, InvalidFormatException {
      HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext()
            .getResponse();
      response.setContentType("application/vnd.ms-excel");
      String headerResponse = "attachment;filename=";
      headerResponse = headerResponse.concat(fileName);
      response.addHeader("Content-disposition", headerResponse);
      ServletOutputStream out = response.getOutputStream();

      Workbook wb = WorkbookFactory.create(inputStream);

      ...........

      wb.write(out);
      out.flush();
      out.close();
      context.responseComplete();



The excel file is generated, so everthing is fine. But since I put ajax="false" the flag oncomplete="myJavascriptFunction()" does not work, so how can I call a javascript function once the excel file has been downloaded ? Is it even possible ???

The funny thing is that when I put ajax="true" the javascript function is called, but the file is not downloaded !!!

I have searched in the PrimeFaces user's guide, there I found that CommandButton component submits it's enclosed form, so I tried specifying the javascript function in the onsubmit flag of the form, but this function is not called after but before the file is generated. So this option does not solve my problem.

Has anyone any idea ???

Thx
JSF : Mojarra 2.0.4 (FCS b09)
Primefaces : 3.3
Tomcat : 7.0.27 & Weblogic : 10.3.3


Posts: 5976
My recommendations are as follows:

1. Read this: http://balusc.blogspot.com/2009/05/javajspjsf-and-javascript.html

2. Google the following:

jsf balusc h:outputscript onload

3. Use JSF and AJAX to replace any/all need to do any JavaScript. I used to love JavaScript when I was first tasked to work on a web application (with good old Sybase PowerBuilder and EAServer), but now I love Java Server Faces and PrimeFaces MUCH MUCH MORE!!!!!!!!!!!!!


BalusC (user ID or screen name) is a JSF developer and he recommends using JSF (instead of JSPs), but he has been writing blogs and answering questions related to JSF and JSP for years now. I hope that helps.
Howard

PrimeFaces 5.1, Extensions 3.0.0, Push (Atmosphere 2.2.3)
TomEE+ 1.7.1 (Tomcat 7.0.55), MyFaces Core 2.2.5, JDK8
JUEL 2.2.7 | OmniFaces | EclipseLink-JPA/Derby | Chrome

Java EE 6 Tutorial|NetBeans|Google|Stackoverflow|PrimeFaces|Apache


Posts: 5
Hi smithh032772,

first of all thank you very much for your answer, but I'm afraid I must use javascript for the file downloading. According to this post of BalusC : "You cannot download files with JS/ajax. JS can't do anything with the obtained binary response as it cannot force a Save as dialogue (thank god)." I found it here :

http://stackoverflow.com/questions/7422 ... d-response

I could use ajax to call the method generating the file, but that would mean the client should connect to the server to get the file, and he won't accept that solution.

What I really need is to call a javascript function once the response arrives to the browser, (not in the server side), (exactly the same behaviour that the oncomplete does if I could use Ajax). I don't even know if it's possible !

Normally I use Ajax, but for file downloading I can not use it, so I don't really know how to call a js function once the response arrives to the browser.

Maybe I could user another primefaces element instead of the p:commandButton, but what is certain is that I can not use Ajax.

<p:commandButton id="extractionDataRegional" 
         actionListener="#{exportController.doExport}" ajax="false"
         oncomplete="myJavascriptFunction()"
         value="Do export" update="messages"  />


Thx a lot
JSF : Mojarra 2.0.4 (FCS b09)
Primefaces : 3.3
Tomcat : 7.0.27 & Weblogic : 10.3.3


Posts: 5976
You're welcome. Can you respond with the Javascript function/method definition that needs to be called "oncomplete" (or after) p:commandButton (below)?

<p:commandButton id="extractionDataRegional" 
         actionListener="#{exportController.doExport}" ajax="false"
         oncomplete="myJavascriptFunction()"
         value="Do export" update="messages"  />


I'm trying to understand the flow here. Hmmm, commandButton to generate Excel file on the server, and then you are not allowed to make another server hit to download the generated-Excel-file from server to the client? If you want enduser or client to click one button to Generate-and-Download file, then you should be able to complete that with the following PrimeFaces 2.2.1 showcase example at the URL below. Right?

http://www.primefaces.org/showcase/ui/fileDownload.jsf

You should be able to add your code below in the FileDownloadController (that is demonstrated in the showcase example at the URL above). Right?


   public static void doExport() throws IOException, InvalidFormatException {
      HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext()
            .getResponse();
      response.setContentType("application/vnd.ms-excel");
      String headerResponse = "attachment;filename=";
      headerResponse = headerResponse.concat(fileName);
      response.addHeader("Content-disposition", headerResponse);
      ServletOutputStream out = response.getOutputStream();

      Workbook wb = WorkbookFactory.create(inputStream);

      ...........

      wb.write(out);
      out.flush();
      out.close();
      context.responseComplete();
Howard

PrimeFaces 5.1, Extensions 3.0.0, Push (Atmosphere 2.2.3)
TomEE+ 1.7.1 (Tomcat 7.0.55), MyFaces Core 2.2.5, JDK8
JUEL 2.2.7 | OmniFaces | EclipseLink-JPA/Derby | Chrome

Java EE 6 Tutorial|NetBeans|Google|Stackoverflow|PrimeFaces|Apache

andyba User avatar
Expert Member

Posts: 2289
Location: Steinfeld, near Bremen/Osnabrück, DE

I think it is mentioned in both the PF3 RC 4 User Guide and Showcase that fileDownload does not work with AJAX ie you must have ajax="false" set for it to work.
Things like onSuccess and onError cannot work in this case because they provide handlers for AJAX events. This explains why they don't work for you.

Sorry to ask this but exactly how do you expect to provide content from the server without actually hitting the server for it?
PF 3.4.2, PF 3.5.10, PF 4.x (Elite versions)
Glassfish 3.1.2.2, Mojarra 2.x, under both Java 6 and Java 7.
If you haven't read the forum rules read them now
My blog: http://onthefaceofthings.blogspot.de/
PrimeFaces Project


Posts: 5
Hi again,

thank you everybody for your answers. I think I didn't explain myself very well, sorry, here I come again with my problem :

I need a button to allow clients to download a file, so my button calls a java method which insert the file in the response, so the user can download it. So using the p:commandButton for calling a java method I get what I need, cool !!!

With the java code I posted in my first post and this code I get what I need


<p:commandButton id="extractionDataRegional" 
         actionListener="#{exportController.doExport}" ajax="false"
         value="Do export" update="messages"  />


At this point users can click the "Do export" button and download the file exactly as shown in this primefaces showcase example

http://www.primefaces.org/showcase/ui/fileDownload.jsf

Everything is OK at this point, users can download the files.

Now, and here cames the problem, I need to mesure the time between the moment the user clicks on the button and the file arrives to the client browser, (yeah, the client wants to know the whole time including network transfert .... ). I have a function called on the onclick to mesure the moment in which the user clicked the button. Now I need to call another js function to know when the file arrived to the client browser and call a servlet to log that times in a file.

I tried adding the onclick and the oncomplete to the p:commandButton :


<p:commandButton id="extractionDataRegional" 
         actionListener="#{exportController.doExport}" ajax="false"
         value="Do export" update="messages"
         onclick="startTime()"
         oncomplete="endTime()"  />


The startTime() function is called when the users clicks the button, but the endTime() function is never called.

When I use put ajax="true" both functions are called, but the file is not downloaded :'(

So my question is : is there anyway to call a js function when a response to a non Ajax request (sent by clicking a p:commandButton (ajax="false")) arrives to the client browser ??? Maybe is simply impossible !!!

I hope I explained myself now :p


By the way, in other page I have a p:commandButton which updates a table and I can perfectly mesure the time between the moment the user clicks the button and the response arrives to the client browser because I use Ajax.

<p:commandButton id="updateTableButton" 
         actionListener="#{tableController.updateTable}" ajax="true"
         value="Update Table" update="infoTable"
         onclick="startTime()"
         oncomplete="endTime()"  />
JSF : Mojarra 2.0.4 (FCS b09)
Primefaces : 3.3
Tomcat : 7.0.27 & Weblogic : 10.3.3


Posts: 5976
Wow, interesting client requirement and nice response (with details) from you, thanks. A few days ago, I did something like as listed below; you may be able to do the same.

1. keep ajax="false" (for full page refresh...smile)
2. Add some type of boolean attribute to your bean (bean.beforeExport, default value = true, in constructor)
3. When user clicks button to begin download/export, beforeExport = false
4. After p:commandButton responds (via ajax="false" request), update the HTML <body> or DOM window.onload = endTime()

http://stackoverflow.com/questions/5570180/jsf-2-0-javascript-onload-oncomplete

5. You can maybe use h:outputScript and use #{bean.javaScriptOnLoad}
6. In bean.getJavaScriptOnLoad(), change your javascript based on bean.beforeExport value.

Sadly, this potentially becomes a browser-dependent solution (and requirement, too), since all JavaScript are not handled the same way by all browsers. :(
Howard

PrimeFaces 5.1, Extensions 3.0.0, Push (Atmosphere 2.2.3)
TomEE+ 1.7.1 (Tomcat 7.0.55), MyFaces Core 2.2.5, JDK8
JUEL 2.2.7 | OmniFaces | EclipseLink-JPA/Derby | Chrome

Java EE 6 Tutorial|NetBeans|Google|Stackoverflow|PrimeFaces|Apache

andyba User avatar
Expert Member

Posts: 2289
Location: Steinfeld, near Bremen/Osnabrück, DE

You won't be able to solve this problem with AJAX simply because the download request is what you are trying to measure and all the action is happening in isolation.

There is however no reason to give up hope.
An approximation for the download duration can be obtained on the server side but you are going to have to be prepared to provide an extended InputStream class that keeps track of the time between the first read from the stream to the time the last read occurs, the stream is closed or an operation on the stream caused an exception.
I would use a Delegate to do this (most IDE's make delegating method calls really easy and the rest of the code should be simple)
You can then easily bubble the Download duration back to the client using a FacesMessage.
PF 3.4.2, PF 3.5.10, PF 4.x (Elite versions)
Glassfish 3.1.2.2, Mojarra 2.x, under both Java 6 and Java 7.
If you haven't read the forum rules read them now
My blog: http://onthefaceofthings.blogspot.de/
PrimeFaces Project


Return to General