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+.
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:
DOCX
.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.