0

Is there a way to make an animated gif image disappear after some server side Java code is executed and the client gets an HTTP Response from the webserver without using Ajax?

I´m using the following Struts2 submit button:

<s:submit value="show Data" onclick="myJsFunction()" />

Method to appear the animated gif image:

function myJsFunction(){  
    $("#containerWithGifImage").fadeIn("fast");  
} 

Method to disappear the animated gif image (but I have no idea, how I can call it without Ajax):

 function myJsFunction2(){  
     $("#containerWithGifImage").fadeOut("fast");  
 }  

Now the gif appears but it is not disappeared after the java code on the webserver was executed.

Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • 1
    how are you calling `myJsFunction2` – Jaromanda X Jan 27 '16 at 08:40
  • You are submiting a form so that's not how it works. For removing/hiding content page displayed element, you need to use ajax otherwise submiting the form will redirect/refresh current page (showing gif image again in your case, i suppose)... You could eventually pass query parameter through form action, but not sure what you are really expecting here – A. Wolff Jan 27 '16 at 08:44
  • When the server is working the action is executed and after it returns a result that would probably redirect you to another page. – Roman C Jan 27 '16 at 09:05
  • @RomanC: It is necessary to stay on the same webpage after the action is executed ! –  Jan 27 '16 at 09:18
  • @Marwief Then you need to execute action in the new window. – Roman C Jan 27 '16 at 09:36

1 Answers1

0

Both your questions (this and the other one) are examples of the XY problem.

Before looking for specific technologies, techniques or hacks, start defining clearly your goal:

The Goal

  1. Download a file without moving to other pages;
  2. Meanwhile, showing an indicator (progress bar, animated gif, overlay, etc...);
  3. When the file has been downloaded, hide the indicator.

The Solution

Bound your trigger to a javascript function as described here:

<a href="javascript:myJsFunction();"> download </a>

In your Javascript function: show the indicator, start a timer to check if the download is over (and then hide the indicator), and download the file:

 function myJsFunction(){

    $("#containerWithGifImage").fadeIn("fast"); // Show the indicator

    setInterval(function(){
        $.ajax({
                url : "/isDownloadFinished.action", type : "GET",
            success : function(data,textStatus,jqXHR) {
                $("#containerWithGifImage").fadeOut("fast"); // Hide the indicator
            },error : function(jqXHR, textStatus, errorThrown) {
                console.log("Download is still in progress, do nothing..."); 
            }
        }); 
    }, 1000); // Check every second if download has finished

    window.location='/download.action'; // Start the download
}

Download.action must put in the session an attribute indicating the download has started, updating it when it's over.
Since with the stream result you're consigning the control of the response to the browser (and hence you can't run code when it has finished), you can write directly to the response and then return NONE, as described here:

public class Download extends ActionSupport implements SessionAware, ServletResponseAware {

    @Setter private Map session;
    @Setter private HttpServletResponse response;

    public String execute(){
        ServletOutputStream os = null;
        try {
            session.put("DOWNLOAD_STATUS","active");
            response.setContentType("myContentType"); 
            response.addHeader("Content-Disposition", "attachment; filename=\"foo.bar\"");
            os = response.getOutputStream();
            IOUtils.copy(getMyFileInputStreamSomeHow(), os);
        } finally {
            IOUtils.closeQuietly(os);
            session.put("DOWNLOAD_STATUS","finished");
        }
        return NONE;
    }
}

You can also have the browser drawing a progressbar for you by specifying the Content-Length response header (response.setHeader("Content-Length", 1337);) as described here, where you can also see a similar mechanism to prevent concurrent downloads.

In the IsDownloadFinished.action, you need to check the session attribute. I it doesn't exist or is different from finished, it means the download is not started yet, or still in progress, hence do nothing. Otherwise, return a succesfull httpheader that will make your jQuery $.ajax function to run the success: callback. You can use either httpHeader or json, as described here:

@Results({
    @Result(name = ActionSupport.SUCCESS, type="httpheader", params = {"status", "200"}),
    @Result(name = ActionSupport.ERROR,   type="httpheader", params = {"error",  "500"})
})
public class IsDownloadFinished extends ActionSupport implements SessionAware {

    @Setter private Map session;

    public String execute(){            
        if ("finished".equals(session.get("DOWNLOAD_STATUS")) {
            session.remove("DW_STATUS");
            return SUCCESS;
        }
        return ERROR;
    }
}

There are different solutions to this problem, I've shown you the simplest one.
More elegant and complex solutions would involve long-held requests and Comet techniques (read: WebSocket), but I suppose you can start with the polling-timer from this kick-off example, customizing it for your needs, and eventually evolving it when more comfortable with the argument.

Community
  • 1
  • 1
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243