Search code examples
javascriptexcelfirefoxexport-to-excel

Excel export in JavaScript using Blob not working in FireFox


I have some JavaScript code as given under first code snippet, that works in latest Chrome but not in latest FireFox. This code is exporting data to xls file using Blob object. The strange thing is that in FireFox, the code does not throw any error but does nothing as it executes all the lines successfully i.e. no export happens.

A demo for this question is at this URL: http://js.do/sun21170/84920

If you run the code in above demo in Chrome, it will download the file newfile.xls ( allow popups in Chrome).

Question: What change I need to make in Blob Code given below, in order to make it work in FireFox? I tried using type: 'application/octet-stream' and also type: 'text/plain', but both did not help in FireFox.

The variable table in code snippet below holds a string that is the html for rendering a table including html and body tags.

Blob Code for exporting (not working in FireFox)

 //export data in Chrome or FireFox
 //this works in Chrome but not in FireFox
 //also no errors in firefox
 sa = true;
 var myBlob =  new Blob( [table] , {type:'text/html'});
 var url = window.URL.createObjectURL(myBlob);
 var a = document.createElement("a");
 document.body.appendChild(a);
 a.href = url;
 a.download = "newfile.xls";
 a.click();
 window.URL.revokeObjectURL(url);

Solution

  • The answer to my question is as explained below.

    The problem was that the line window.URL.revokeObjectURL(url) was being called too soon for FireFox to react to a.click() and show it's file dialog. So, I just added a delay by using setTimeout for the line window.URL.revokeObjectURL(url). This change made it work in FireFox. Of course, it worked in Chrome also.

    The updated code is as below which has only one change in the last line of code. Also, the demo with this change that works in FireFox is: http://js.do/sun21170/84977

    Blob Code for exporting (this works in FireFox and Chrome)

     //export data in Chrome or FireFox
     //this works in Chrome as well as in FireFox
     sa = true;
     var myBlob =  new Blob( [table] , {type:'text/html'});
     var url = window.URL.createObjectURL(myBlob);
     var a = document.createElement("a");
     document.body.appendChild(a);
     a.href = url;
     a.download = "newfile.xls";
     a.click();
    //adding some delay in removing the dynamically created link solved the problem in FireFox
     setTimeout(function() {window.URL.revokeObjectURL(url);},0);
    

    While the above code works perfectly, I think when exporting to xls file, it's better to use type:'application/vnd.ms-excel even though the table variable holds a html string.

    This small change makes FireFox automatically use Excel as the default program for opening the exported file else FireFox uses Laucnch Windows app (default) to open the file. This default app on my laptop was Edge browser.

    var myBlob =  new Blob( [table] , {type:'application/vnd.ms-excel'});
    

    If you would like to use 100% client-side approach in older IE browsers, then Blob object cannot be used since it's not available in older IE browsers, but you can use another approach as in code snippet below.

    Exporting Html to Excel in IE <= IE 11 including IE 8 and IE 9

    function ExportTabletoExcelInOldIE(table) 
    {
     //table variable contains the html to be exported to Excel
     var sa = null;
     var ua = window.navigator.userAgent;
     var msie = ua.indexOf("MSIE ");
     if (msie > 0)  // If old Internet Explorer including IE 8
        {
            //make sure you have an empty div with id of iframeDiv in your page
            document.getElementById('iframeDiv').innerHTML = '<iframe id="txtArea1" style="display:none"></iframe>';
            txtArea1.document.open("txt/html", "replace");
            txtArea1.document.write(table);
            txtArea1.document.close();
            txtArea1.focus();
            sa = txtArea1.document.execCommand("SaveAs", true, "DataExport.xls");
            document.getElementById('iframeDiv').innerHTML = "";
        }
     return (sa);
    }
    

    For above IE specific code to work, add following to your page markup.

    Empty Div needed when exporting in older IE browsers

    <div id='iframeDiv'></div>