Friday, November 18, 2016

Ajax like file downloading in Extjs

Last day, I came across a scenario which is implementing a file download functionality in Extjs on a button click and show loading until getting response.

Through ajax call, its not possible because it gives response in a variable as string.

After spending some time on google I've got a solution. Use iframe and cookie.

iframe

Even though iframe exist in DOM, it will be treated like entirely different window. We can initiate file downloading to a hidden frame it is same as happening in the main window. Advantage of using hidden frame is  exception message will not be shown in application. If an error occurs, normally DOM will be inserted with error messages. 

cookie

Cookie is exists in http header. We can set cookie in http response header to indicate file download has been initiated properly.

Content-Disposition: attachment; filename=report.xlsx
Set-Cookie: fileDownload=true; path=/


Now, we can check existence of cookie for success and check iframe html content for failure. 
If browser see attachment in the header, it will start downloading otherwise it will render.  

var body = Ext.getBody();

create an iframe
var frame = body.createChild({
tag:'iframe',
cls:'x-hidden',
id:'hiddenframe-frame',
name:'iframe'
});

Create a form
var form = body.createChild({
tag:'form',
cls:'x-hidden',
id:'hiddenform-form',
action: url,
method: 'POST',
target:'iframe'
});
ff
C
Create input elements for params
form.createChild({ tag:'input', cls:'x-hidden', id:'hiddenform-'+paramName, type: 'text', text: params[paramName], target:'iframe', value: params[paramName], name: paramName });


Submit form
form.dom.submit();

Now start polling for cookie or html content

if (Ext.util.Cookies.get('fileDownload') && Ext.util.Cookies.get('fileDownload')=='true' ) { //Remove cookie Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/'); Ext.util.Cookies.clear('fileDownload',application.contextPath+'/'); //download is success }


if(Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML.length>0){

    Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/');
                Ext.util.Cookies.clear('fileDownload',application.contextPath+'/');
       
        //Cleanup
        Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML = ""; 
       
        //Download is failure
}

See github link FileDownload.js

Usage :
FileDownload.downloadFile({
url : "http://url",
params: {id:"1"},
succcess:function(){
    //Success callback
},
failure: function(){
    //Failure callback
}
});

Let me know if you have any queries.