8

I am facing an issue where I have downloaded an Excel file with Angular 1 but if I am implementing the same code in Angular 5 it is showing the error that your file is corrupted. My response is in ArrayBuffer and I am unable to read the file.

Below is my code:

Service:

 DownloadData(model:requiredParams):Observable<any>{
  const headers = new Headers();
  const requestOptions = new RequestOptions({ headers: headers });
  requestOptions.headers.append('Content-Type', 'application/json');

   const body = JSON.stringify(model);
  return this.http.post(url, body, requestOptions)
  .map((res:any) => res)
 .catch((e: any) => Observable.throw(this.errorHandler(e)));
 }

Component:

exportToExcel() {
    this.loadingOverlayFlag = true;
   this.podashboardService.DownloadData(this.data).subscribe(result=>{
    console.log(result);
    this.downloadFile(result._body,'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'export.xlsx');
  })
  }

 downloadFile(blob: any, type: string, filename: string) {

 var binaryData = [];
   binaryData.push(blob);

     const url = window.URL.createObjectURL(new Blob(binaryData, {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"})); // <-- work with blob directly

     // create hidden dom element (so it works in all browsers)
     const a = document.createElement('a');
     a.setAttribute('style', 'display:none;');
     document.body.appendChild(a);

     // create file, attach to hidden element and open hidden element
     a.href = url;
     a.download = filename;
     a.click();

   }

I am able to download the file, but unable to read its content. The error is:

Microsoft Excel
Excel cannot open the file '███████ DASHBOARD (5).xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file. OK

Stefan Crain
  • 1,873
  • 3
  • 18
  • 22
user5497854
  • 81
  • 1
  • 1
  • 6

3 Answers3

7

I struggle with this one all day. Replace angular HttpClient and use XMLHttpRequest as follows:

var oReq = new XMLHttpRequest();
  oReq.open("POST", url, true);
  oReq.setRequestHeader("content-type", "application/json");
  oReq.responseType = "arraybuffer";

  oReq.onload = function (oEvent) {
    var arrayBuffer = oReq.response;
    if (arrayBuffer) {
      var byteArray = new Uint8Array(arrayBuffer);
      console.log(byteArray, byteArray.length);
      this.downloadFile(byteArray, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'export.xlsx');
    }
  };

  oReq.send(body);

Then modified the creation of the Blob in your downloadFile function:

const url = window.URL.createObjectURL(new Blob([binaryData]));

In your case the service will look something like this:

DownloadData(model:requiredParams):Observable<any>{
  return new Observable(obs => {
    var oReq = new XMLHttpRequest();
    oReq.open("POST", url, true);
    oReq.setRequestHeader("content-type", "application/json");
    oReq.responseType = "arraybuffer";

    oReq.onload = function (oEvent) {
      var arrayBuffer = oReq.response;
      var byteArray = new Uint8Array(arrayBuffer);
      obs.next(byteArray);
    };

    const body = JSON.stringify(model);
    oReq.send(body);
  });
}

Then the component:

exportToExcel() {
  this.loadingOverlayFlag = true;
  this.podashboardService.DownloadData(this.data).subscribe(result=>{
    // console.log(result);
    this.downloadFile(result,'application/vnd.openxmlformats-
    officedocument.spreadsheetml.sheet', 'export.xlsx');
  })
}

downloadFile(blob: any, type: string, filename: string) {

  var binaryData = [];
  binaryData.push(blob);

  const url = window.URL.createObjectURL(new Blob(binaryData, { type: filetype })); // <-- work with blob directly

   // create hidden dom element (so it works in all browsers)
   const a = document.createElement('a');
   a.setAttribute('style', 'display:none;');
   document.body.appendChild(a);

   // create file, attach to hidden element and open hidden element
   a.href = url;
   a.download = filename;
   a.click();
}
Eric D. Johnson
  • 7,181
  • 6
  • 30
  • 41
Ovi
  • 574
  • 6
  • 16
  • This got it to work for me in Edge after it did a repair, but downloading the same file from Chrome it can't repair it. Thanks for getting me a step closer. :) – Eric D. Johnson Aug 21 '18 at 18:12
6

I managed to make it working by using httpClient ( responseType: 'arraybuffer' in the httpOptions did the trick).

createReportBackend() {

    const httpOption: Object = {
      observe: 'response',
      headers: new HttpHeaders({
        'Content-Type': 'application/json'
      }),
      responseType: 'arraybuffer'
    };

    this.httpClient.post('http://localhost:8080/api/report', this.data, httpOption)
      .pipe(map((res: HttpResponse) => {
        return {
          filename: 'Drinks.xlsx',
          data: new Blob(
            [res['body']],
            { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}
          ),
        };
      }))
      .subscribe(res => {
        if (window.navigator.msSaveOrOpenBlob) {
          window.navigator.msSaveBlob(res.data, res.filename);
        } else {
          const link = window.URL.createObjectURL(res.data);
          const a = document.createElement('a');
          document.body.appendChild(a);
          a.setAttribute('style', 'display: none');
          a.href = link;
          a.download = res.filename;
          a.click();
          window.URL.revokeObjectURL(link);
          a.remove();
        }
      }, error => {
        throw error;
      }, () => {
        console.log('Completed file download.');
      });
  }
cisk
  • 451
  • 3
  • 11
0

Easiest way to download exel file found using file-saver is here:

//Declaration
headers: HttpHeaders;
options: any;

 //Constructor or u can have for specific method
 this.headers = new HttpHeaders({ 'Content-Type': 'application/json' });
    this.options = {
        observe: 'response',
        headers: this.headers,
        responseType: 'arraybuffer'
    };

 //Service request:
  this.httpClient.post('http://localhost:8080/api/report', this.data, this.option)
  .pipe(
  catchError(err => this.handleError(err))
    ).subscribe(response => {
        Helper.exportExelFile(response, 'FileName');
    });

//component or in helper function in one class

import * as FileSaver from 'file-saver';
 function exportExelFile(data, filename) {
const blobValue = new Blob([data['body']], {
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
 FileSaver.saveAs(blobValue, filename + '.' + FileType.EXCEL);
}

export const Helper = {
  exportExelFile
   };
Vinutha Kumar
  • 905
  • 1
  • 7
  • 8