js:ajax-like_jquery_file_download

AJAX-like jQuery File Download

jQuery File Download is a file downloader plugin that make the downlaod look like ajax. The way it does the download is to use a hidden html iframe + server edit cookie to signal the front end the download it completed. It is developed by johnculviner.com. Here we only covered what I would like to be covered. For more details, always go to the offical site https://github.com/johnculviner/jquery.fileDownload.

Go to https://github.com/johnculviner/jquery.fileDownload to download the javascript file for the plugin. This plugin need Jquery version 1.6+.

  • Copy the js into your project
  • Include the jQuery 1.6+ and the jquery.fileDownload plugin into your html file. Order matters.

Assume we have a <button type='button' id='btn-save'>Download<button> within a HTML form. and here is what the callback for this button looks like. Let's say

showLoadingModal(); //SHOW YOUR LOADING SCREEN
var form = $(this).closest('form').get(0);
$.fileDownload($(form).prop('action'), {
	httpMethod: "POST",
	data: $(form).serialize(),
	successCallback: function (url) {
		hideLoadingModal(); //HIDE YOUR LOADING SCREEN
		//YOUR SUCCESS CALLBACK, URL IS YOUR REQUSET URL
	},
	failCallback: function (html, url) {
		hideLoadingModal(); //HIDE YOUR LOADING SCREEN
		//YOUR FAIL CALLBACK, html IS THE RESPONSE HTML FROM SERVER, URL IS YOUR REQUSET URL
	},
	abortCallback: function (url) {
		hideLoadingModal(); //HIDE YOUR LOADING SCREEN
		//YOUR ABORT CALLBACK, URL IS YOUR REQUSET URL
	}
});

The url from the client side should be calling one of your controller's method. Assume the client pass an 'id' field to the server. DomainObject can be any of your domain object that mapped to your data source, myService supposed to be any grails server that handle your business logic; MyException could be any of your own exception thrown by your business logic, and DateTimeTools is my own creation to handle date time related function call. Also assume the file we are going to download is a docx.

Basically we need to do:

  • Generate the array of byte for user to download. Should be something related to the submitted HTTP form.
  • Generate the filename of that byte array.
  • Generate the cookie to alert the client side javascript that the file creating is completed. User exactly what we have down in the code section!
  • Put such cookie in the response.
  • Set your file type in the response according to your byte of array file type. The folloing example use DOCX.
  • Write your byte to the response.
  • Flush your response to the client. This step is important because if your byte[] is too small, it might not be sent to the client without a flush, and your client will continue to wait until timeout.
  • If there were any error, send a HTTP 503 back to the client.
def myFunction(DomainObject domainObject) {
	try {
            byte[] yourBytes = //get the byte of array in your own way, may be to do something with your domainObject or database.
            String filename = "YOUR_FILE_NAME.docx"
            
            //Setup cookie to alert the client side.
            Cookie cookie = new Cookie( 'fileDownload', 'true' )
            cookie.path = '/'
            cookie.maxAge = 5
            response.addCookie(cookie)

            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename+"\"")
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document")
            
            response.outputStream.write(yourBytes)
            response.outputStream.flush() //Flushing is important! because the server
	}catch (MyException e) {
		response.sendError(503, "Fail to download. Please try again later.  ${e.getMessage()}")
	}catch (Exception e) {
		log.error("Time: ${DateTimeTools.getSystemCurrentTime()} myFunction: ${e.getMessage()}", e)
		response.sendError(503, "Fail to download. Please try again later.")
	}
}

Since there is only one cookie to tell the download is completed. If there is multiple tabs in the same web browser window download the files from the same site with this plugin, the plugin would not know what tab really finished the download, and one of the tab will call its successCallback, or failCallback wrongly. The actual download action will not be affected though.

  • js/ajax-like_jquery_file_download.txt
  • Last modified: 2018/11/08 10:01
  • by chongtin