Avatar of roger v
roger v
Flag for United States of America asked on

Adding download link for downloading excel file retrieved from database

I've got an excel file stored in base64, that is retrieved in a jquery ajax.get call. The base64 data is then converted back into .xlsx file, and attached to a download <a> tag, for the user to click and download the .xlsx file. I get 2 errors: the first error is: jquery.min.js:3 Uncaught TypeError: Cannot read property 'createDocumentFragment' of null.

The 2nd error happens when I click on the download link: Uncaught DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
Not sure if 2nd error is related to the 1st one or not. My code is as following:

HTML code:

<a id="downloadlink" onClick="return DownloadExcel()">Download Excel File</a> 

Open in new window


JS code:

//download excel func
function DownloadExcel( file, filename) {
    //debugger;
    var blob = base64toBlob(file, "data:application/vnd.ms-excel;")
    if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
        return navigator.msSaveOrOpenBlob(blob, filename);
    }
    else{
        console.log("inside else of downloadexcel");
      var objectUrl = URL.createObjectURL(blob);
        var downloadLink = $("#downloadlink");
        downloadLink.href = objectUrl; //uri;
        downloadLink.download = filename;
       // document.body.appendChild(downloadLink);
       $(document).append(downloadLink);
    }
  }
  
  function base64toBlob(b64Data, contentType, sliceSize) {
    contentType = contentType || '';
    sliceSize = sliceSize || 512;
  
    var byteCharacters = atob(b64Data);
    var byteArrays = [];
  
    for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
      var slice = byteCharacters.slice(offset, offset + sliceSize);
  
      var byteNumbers = new Array(slice.length);
      for (var i = 0; i < slice.length; i++) {
        byteNumbers[i] = slice.charCodeAt(i);
      }
  
      var byteArray = new Uint8Array(byteNumbers);
  
      byteArrays.push(byteArray);
    }
    var blob = new Blob(byteArrays, {
      type: "application/vnd.ms-excel"
    });
    return blob;
  }
  // /download excel func

  $(document).ready(function(){ 

    $.ajax({
            url: "https://myserver.com/files/file.cfc?fileid=12",
            type: "GET",
            dataType: "json",
            cache: false,
            success: function(response){
                if(response.length != 0){
                    console.log("Successful file retrieval!");
                  
                   DownloadExcel( response[0].filecontent, response[0].filename  );    
                   
                }
                else{
                    console.log("Error in file retrieval!");
                    console.log( response );
                }
            },
            error: function( response ){
                console.log("There was an API server error!");
                console.log( response );
            }
        });
  });

Open in new window

JavaScriptjQuery

Avatar of undefined
Last Comment
roger v

8/22/2022 - Mon
roger v

ASKER
Update: The 2nd error that was being generated is related to the 1st error: I confirmed this by removing the code to attach the event to <a>, and instead did the conversion of the base64 file into .xlsx, and the conversion part works and the .xlsx file is downloaded without error to user computer. Now I need to figure out a way to actually trigger this download upon user clicking a <a href> tag.
SOLUTION
roger v

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
ASKER CERTIFIED SOLUTION
Julian Hansen

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
roger v

ASKER
Thanks for the great explanation! I've changed the way I'm building the <a href> tag and it's working now. But I'll go through your answer and try that out as well. thanks as always!

roger
Julian Hansen

I have put a working sample here
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Julian Hansen

Your original approach was much better - the new way is a bit of a hack I would go with what you had and just make those small adjustments.

Why - your AJAX complete has become very "heavy" - the functions that are now local with respect to the complete handler are potentially functions you want to reuse. I always try to make my complete handlers very lightweight and put the supplementary code in a library or module.
roger v

ASKER
Roger Wilco!