11 Replies Latest reply on Sep 16, 2011 11:36 AM by cobar

    A4J w/ Excel Output from a CommandLink

      So I have a complex custom data table that I needed to export and I was able to do it successfully using the method described here:
      http://wiki.apache.org/myfaces/Exporting_DataTable_To_MS-Excel

      Before, I was exporting it from a servlet, but that wasn't exactly what I wanted. The problem is if I use an A4J command link or attempt to change an A4J drop down to generate another table after clicking on the command link , I end up with the raw Excel file spit out. This is likely because the excel export leaves things ... in a messed up state.

      Is there a proper way to get these to work together. Any ideas? I've been bashing my head against this for hours and I can't think of another way to do it.

        • 1. Re: A4J w/ Excel Output from a CommandLink

          do you want to post the code snippet of your page here?

          • 2. Re: A4J w/ Excel Output from a CommandLink

            I can do better then that. Here is a zip containing a demo program w/ an example of the code itself.

            http://notpublic.zy.ca/demo.zip

            In addition to Ajax4JSF (1.1.0), it needs Jakarta POI (for the excel bit). I'm currently using 3.0.0 alpha3, but it was occurring under 2.5.1 final as well and this example isn't embedding images so there is no point going to 3.0.0 alpha3.

            Downloadable here:
            http://www.apache.org/dyn/closer.cgi/jakarta/poi/

            • 3. Re: A4J w/ Excel Output from a CommandLink

              I'm pretty sure what is causing the problem is this bit in the action:

              FacesContext fc = FacesContext.getCurrentInstance ();
              HttpServletResponse response = (HttpServletResponse)fc.getExternalContext ().getResponse ();
              response.setHeader ("Content-disposition", "attachment; filename=test.xls");
              response.setContentType ("application/vnd.ms-excel");
              ServletOutputStream out = response.getOutputStream ();

              ...

              wb.write (out);
              out.close ();
              fc.responseComplete ();

              It is changing the JSF state ... and thus invalidating the A4J stuff ... going to the page again fixed the problem ... but there has to be a way to do this without messing everything up.

              • 4. Re: A4J w/ Excel Output from a CommandLink
                scottstevenson

                Has anyone come up with a workaround for this? I'm encountering a similar problem.

                • 5. Re: A4J w/ Excel Output from a CommandLink

                  Nope, not yet. There was another thread where a solution was suggested, but it didn't work.

                  • 6. Re: A4J w/ Excel Output from a CommandLink

                    Works!

                    Don't use actions, use a PhaseListener. Intercept a request to the page, mark it somehow (in my test, i added a parameter ?export and looked for that ... I used a normal link). And then use what you had in the action to generate the file. Everything is still there in the viewstate and your a4j actions still work fine.

                    • 7. Re: A4J w/ Excel Output from a CommandLink
                      scottstevenson

                       

                      "harnishg" wrote:
                      Works!

                      Don't use actions, use a PhaseListener. Intercept a request to the page, mark it somehow (in my test, i added a parameter ?export and looked for that ... I used a normal link). And then use what you had in the action to generate the file. Everything is still there in the viewstate and your a4j actions still work fine.


                      Thanks a lot for posting this. I'll give it a go. Do you have a sample of your PhaseListener code?



                      • 8. Re: A4J w/ Excel Output from a CommandLink

                        Sure:

                        public class ExcelExportPhaseListener
                         implements PhaseListener
                        {
                         public void afterPhase (PhaseEvent phaseEvent)
                         {
                         FacesContext facesContext = phaseEvent.getFacesContext ();
                         Map map = facesContext.getExternalContext ().getRequestParameterMap ();
                        
                         if(map.containsKey ("exportToExcel"))
                         {
                         try
                         {
                         // Create Workbook
                         HSSFWorkbook wb = new HSSFWorkbook ();
                         HSSFSheet sheet = wb.createSheet ("example");
                        
                         // YOUR EXCEL CODE HERE
                        
                         // IIRC, this could be a portal reponse as well, but I'm not in a portal environment so all is good.
                         HttpServletResponse contextResponse = (HttpServletResponse)facesContext.getExternalContext().getResponse();
                        
                         contextResponse.setHeader ("Content-disposition", "attachment; filename=test.xls");
                         contextResponse.setContentType ("application/vnd.ms-excel");
                        
                         wb.write (contextResponse.getOutputStream());
                         facesContext.getApplication().getStateManager().saveSerializedView(facesContext);
                         facesContext.responseComplete();
                         }
                         catch (Exception e)
                         {
                         throw new RuntimeException ( e );
                         }
                         }
                         }
                        
                         public void beforePhase (PhaseEvent phaseEvent)
                         {
                         //do nothing
                         }
                        
                         public PhaseId getPhaseId ()
                         {
                         return PhaseId.RESTORE_VIEW;
                         }
                        }
                        


                        • 9. Re: A4J w/ Excel Output from a CommandLink

                          Then I used a link like this to call it

                          <f:verbatim><a href="?exportToExcel">Export</a></f:verbatim>
                          


                          I'm using JSF1.1 so I think there are better ways to do that in JSF 1.2 and Facelets.

                          • 10. Re: A4J w/ Excel Output from a CommandLink
                            kristof.devos

                            Can you show how you do the rerender after the file is downloaded?

                            thx

                            • 11. Re: A4J w/ Excel Output from a CommandLink
                              cobar

                              This will only work with a non bounded component.

                               

                              <h:outputLink id="attchVwLnk">

                                    <f:param id="ata3" name="attachId" value="64"/>

                                    <h:outputText id="atFlNm" value="View"/>

                                </h:outputLink>

                               

                              It will not work with bounded component.

                                <h:outputLink id="attchVwLnk">

                                    <f:param id="ata3" name="attachId" value="#{attach.id}"/>

                                    <h:outputText id="atFlNm" value="#{attch.fileName}"/>

                                </h:outputLink>

                               

                              Binding the component changes the outputLink to a POST which for me resulted in a duplicate ID exception for which the specified form:j_id831 does not exist in the page source.