4

The problem is very simple: i have to download a file when i submit a form, it's an ajax call when the form is submitted which lets me build a file with the data taken from the form, server side, and then send it as a link to an alert. The fact is that my boss want the file to be downloaded directly and not through a link in an alert. So i had to make sure that the file is available server side through tornado(web):

        self.set_header('Content-Type', 'application/octet-stream')
        self.set_header('Content-Disposition', 'attachment; filename=clients_counter.zip')
        with open("static/clients_counter.zip", 'r') as f:
            while True:
                data = f.read()
                if not data:
                    break
        self.write(data)
        self.finish()

The server side code seems to work fine, but the client side (extjs4.1) is really a nightmare. This is how my ajax call looks like now, and it doesn't work:

Ext.Ajax.request({
method : "GET",
url : 'http://whatever.com/count?client='+client+'&start='+start+'&end='+end,
timeout : 30000,
success :
         function (response) {
    //Ext.Msg.alert(response.responseText);
            desktop.getWindow('count-win').doClose();
            return response;
       }//handler,
     failure : 
     function(response) {
    alert("Wrong request");
    }});
softwareplay
  • 1,379
  • 4
  • 28
  • 64
  • 3
    It's not Ext JS; in fact no browser will initiate file download off an Ajax call. The standard way to do this is to create an invisible form and submit it. – Alex Tokarev Dec 10 '13 at 22:13

7 Answers7

12

After reading on various sources from Ext JS forum and here in stackoverflow, below is the approach I've chosen (using Ext JS version 4.2.1):

downloadFile: function(config){
    config = config || {};
    var url = config.url,
        method = config.method || 'POST',// Either GET or POST. Default is POST.
        params = config.params || {};

    // Create form panel. It contains a basic form that we need for the file download.
    var form = Ext.create('Ext.form.Panel', {
        standardSubmit: true,
        url: url,
        method: method
    });

    // Call the submit to begin the file download.
    form.submit({
        target: '_blank', // Avoids leaving the page. 
        params: params
    });

    // Clean-up the form after 100 milliseconds.
    // Once the submit is called, the browser does not care anymore with the form object.
    Ext.defer(function(){
        form.close();
    }, 100);

}
sakadas
  • 539
  • 4
  • 13
  • 1
    I insert this function in a mixin to be more portable: https://gist.github.com/oniram88/10730767 – Oniram Apr 15 '14 at 13:06
  • Is there anyway to apply a "processing download" mask when downloading a file? – VAAA Jul 07 '14 at 19:00
  • I doubt it is possible with the solution above since the form is closed soon after the browser starts downloading the file. – sakadas Jul 17 '14 at 18:53
  • I know this is old, but is there any way to include jsonData in the standard submit somehow? I can do it with `Ext.Ajax.request` but can't figure out how to get it to work with `form.submit`... – pennstatephil Mar 13 '15 at 21:00
  • i put that into a code and my browser (FireFox) does not download anything, it just opened it in another tab. – g07kore May 12 '15 at 15:49
  • g07kore - I just tried it on my end. It is kinda weird. It does open a new tab in firefox, immediately closed the new tab, and showed a download dialog box. So it worked but with a little twist. What version of firefox are you using? I am using 38.0.1 – sakadas May 29 '15 at 01:57
  • I added this code in my program, It doesn't work for me. When click button, It does nothing. – Sudhakar May 21 '16 at 07:44
  • @Sudhakar what is the value in the config.url? Does your browser download it on its own using the same url value? – sakadas May 25 '16 at 08:22
  • Ur a legend my friend :) you just solved my problem that I was working on for hours. Thank you.. @sakadas +1 – sticky_elbows Sep 07 '18 at 14:08
6

I had a similar problem trying to download an Excel File in an Ajax call I solved it this way:

Make a standard sumbit instead of Ajax.

var form = Ext.create('Ext.form.Panel', { // this wolud be your form 
    standardSubmit: true,         // this is the important part 
    url: '../ObtenerArchivoAdjuntoServlet' 
});

form.submit({
    params: {
       nombreArchivo: nombreArchivo
    }
});

After this you would be able return the desired file.

Ashish Aggarwal
  • 3,018
  • 2
  • 23
  • 46
code4jhon
  • 5,725
  • 9
  • 40
  • 60
  • 1
    You don't get to handle the response since it is a standard submit. I thought the same the first time I faced it, look: http://stackoverflow.com/questions/18434962/extjs-handling-success-or-failure-when-doing-a-standard-submit-in-a-form – code4jhon May 04 '14 at 01:21
  • 1
    Is there a way to implement a "processing file" mask? – VAAA Jul 07 '14 at 19:00
3

After extracting/reading many posts, I managed to get this simple method to work..

                Ext.create('Ext.form.Panel', {
                    renderTo: Ext.getBody(),
                    standardSubmit: true,
                    url: 'URL'
                }).submit({params: {'PARAM1': param1, 'PARAM2': param2}});
John
  • 71
  • 2
  • Yes, that works fine. If you are using Sencha Cmd to build you will need to require 'Ext.form.action.StandardSubmit' also. Thanks and to all above also. – Murrah Sep 02 '14 at 05:55
2

I think you can take a much easier solution. Forget about the ajax, and just get plain old js to open the file for you:

window.open('http://whatever.com/count?client='+client+'&start='+start+'&end='+end)

This will open a new tab and start the download from there.

Kyle Fransham
  • 1,859
  • 1
  • 19
  • 22
1

The following code used to download the file using extjs 5 or 6. Add the following code to method and invoke this for button action. This downloads the file directly insteadof opening in new tab.

use an iframe like this:

/**
 * prints the file
 */
printReport: function () {
    var url = 'downloadURL';
    Ext.Ajax.request({
        url: url,
        method: 'GET',
        autoAbort: false,
        success: function(result) {
            if(result.status == 204) {
                Ext.Msg.alert('Empty Report', 'There is no data');
            } else if(result.status == 200) {
                Ext.DomHelper.append(Ext.getBody(), {
                    tag:          'iframe',
                    frameBorder:  0,
                    width:        0,
                    height:       0,
                    css:          'display:none;visibility:hidden;height:0px;',
                    src:          url
                });
            }
        },
        failure: function() {
            //failure here will automatically
            //log the user out as it should
        }
    });
}

Copied the answer from extjs forum

Option:2 If you want to open the file in new tab

    /**
 * open file in tab
 */
openReport: function () {
    var url = 'downloadURL';
    Ext.Ajax.request({
        url: url,
        method: 'GET',
        autoAbort: false,
        success: function(result) {
            if(result.status == 204) {
                Ext.Msg.alert('Empty Report', 'There is no data');
            } else if(result.status == 200) {
                var win = window.open('', '_blank');
                win.location = url;
                win.focus();
            }
        },
        failure: function() {
            //failure here will automatically
            //log the user out as it should
        }
    });
}
Sudhakar
  • 3,104
  • 2
  • 27
  • 36
1

You cannot use ajax to download file. I've implemented file downloading in extjs which is like ajax. see the blog ajaxlikefiledownload.

FileDownload.downloadFile = function(arguments) {

    var url = arguments['url'];
    var params = arguments['params'];
    var successCallback = arguments['success'];
    var failureCallback = arguments['failure'];

    var body = Ext.getBody();

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

    var form = body.createChild({
        tag:'form',
        cls:'x-hidden',
        id:'hiddenform-form',
        action: url,
        method: 'POST',
        target:'iframe'
    });


    if (params) {
        for (var paramName in params) {     
            form.createChild({
                tag:'input',
                cls:'x-hidden',
                id:'hiddenform-'+paramName,
                type: 'text',
                text: params[paramName],
                target:'iframe',
                value: params[paramName],
                name: paramName
                });
        }
    }
    form.dom.submit();
    FileDownload.isFinished(successCallback,failureCallback);
};


FileDownload.isFinished = function(successCallback,failureCallback) {

//Check if file is started downloading
if (Ext.util.Cookies.get('fileDownload') && Ext.util.Cookies.get('fileDownload')=='true' ) {
    //Remove cookie call success callback 
    Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/');
    Ext.util.Cookies.clear('fileDownload',application.contextPath+'/');
    successCallback();
    return;
} 

//Check for error / IF any error happens then frame will load with content
try {
    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+'/');
        failureCallback();
        //Cleanup
        Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML = ""; 
        
        return;
    }
} 
catch (e) {
    console.log(e);
}

console.log('polling..');
// If we are here, it is not loaded. Set things up so we check   the status again in 100 milliseconds
    
window.setTimeout('FileDownload.isFinished('+successCallback+','+failureCallback+')', 100);
};

Usage :

FileDownload.downloadFile({
  url : url,
  params : params,
  success : function(){
   //Success call back here
  },
  failure : function(){
   //Failure callbak here
  }
});

In the http response you need to add a cookie nammed fileDownload = true

Sergey Bogdanov
  • 525
  • 9
  • 22
Arun Mohan
  • 744
  • 1
  • 9
  • 20
0

I just had to ad to the success function of the ajax request:

window.open('urltothefile.ext')
softwareplay
  • 1,379
  • 4
  • 28
  • 64