I have a page that allows the user to download a dynamically-generated file. It takes a long time to generate, so I\'d like to show a \"waiting\" indicator. The problem is,
This Java/Spring example detects the end of a Download, at which point it hides the "Loading..." indicator.
Approach: On the JS side, set a Cookie with a Max Expiration Age of 2 min, and poll every second for cookie expiration. Then the server-side overrides this cookie with an earlier expiration age -- the completion of the server process. As soon as the cookie expiration is detected in the JS polling, "Loading..." is hidden.
JS Side
function buttonClick() { // Suppose this is the handler for the button that starts
$("#loadingProgressOverlay").show(); // show loading animation
startDownloadChecker("loadingProgressOverlay", 120);
// Here you launch the download URL...
window.location.href = "myapp.com/myapp/download";
}
// This JS function detects the end of a download.
// It does timed polling for a non-expired Cookie, initially set on the
// client-side with a default max age of 2 min.,
// but then overridden on the server-side with an *earlier* expiration age
// (the completion of the server operation) and sent in the response.
// Either the JS timer detects the expired cookie earlier than 2 min.
// (coming from the server), or the initial JS-created cookie expires after 2 min.
function startDownloadChecker(imageId, timeout) {
var cookieName = "ServerProcessCompleteChecker"; // Name of the cookie which is set and later overridden on the server
var downloadTimer = 0; // reference to timer object
// The cookie is initially set on the client-side with a specified default timeout age (2 min. in our application)
// It will be overridden on the server side with a new (earlier) expiration age (the completion of the server operation),
// or auto-expire after 2 min.
setCookie(cookieName, 0, timeout);
// set timer to check for cookie every second
downloadTimer = window.setInterval(function () {
var cookie = getCookie(cookieName);
// If cookie expired (NOTE: this is equivalent to cookie "doesn't exist"), then clear "Loading..." and stop polling
if ((typeof cookie === 'undefined')) {
$("#" + imageId).hide();
window.clearInterval(downloadTimer);
}
}, 1000); // Every second
}
// These are helper JS functions for setting and retrieving a Cookie
function setCookie(name, value, expiresInSeconds) {
var exdate = new Date();
exdate.setTime(exdate.getTime() + expiresInSeconds * 1000);
var c_value = escape(value) + ((expiresInSeconds == null) ? "" : "; expires=" + exdate.toUTCString());
document.cookie = name + "=" + c_value + '; path=/';
}
function getCookie(name) {
var parts = document.cookie.split(name + "=");
if (parts.length == 2 ) {
return parts.pop().split(";").shift();
}
}
Java/Spring Server Side
@RequestMapping("/download")
public String download(HttpServletRequest request, HttpServletResponse response) throws Exception {
//... Some logic for downloading, returning a result ...
// Create a Cookie that will override the JS-created Max-Age-2min Cookie
// with an earlier expiration (same name)
Cookie myCookie = new Cookie("ServerProcessCompleteChecker", "-1");
myCookie.setMaxAge(0); // this is immediate expiration,
// but can also add +3 sec. for any flushing concerns
myCookie.setPath("/");
response.addCookie(myCookie);
//... -- presumably the download is writing to the Output Stream...
return null;
}