20

I've an API which returns an Excel document as response. The request will be one simple JSON.

I've searched Google and found some code base to download the file and I've used it in my application, but I'm getting some errors and unable to find it out the solution. Below is my code base:

component.ts

import rxjs/Rx;

details = {id: 75,name: "some name"}

this.nameService.getData(this.details).subscribe(response => {
this.downloadFile(response);
})

downloadFile(data: Response) {
  const blob = new Blob([data], { type: '.xlsx' });
  const url= window.URL.createObjectURL(blob);
  window.open(url);
}

nameService.ts

getData(postData) {
  return this.httpService.post('https://localhost:8080/getFile/', postData);
}

httpService.ts

constructor(private http: HttpClient)
post(apiEndpoint: string, request: any) :Observable<any> {
 return this.http.post<any>(apiEndpoint,request);
}

with the above code base I'm getting below two errors and the file is not downloaded.

  1. Getting the error :

"Type Response is not assignable to type Blobpart" in creating the Blob(const blob = new Blob([data], { type: '.xlsx' });)

  1. If I change the data as any (downloadFile(data: any)) the above error(1) will go but I'm getting an httperror response as 'Syntax error: unexpected token P in json at position 0 at json.parse

Kindly help if anyone finds any solution to the above issues.

7 Answers 7

18
  1. You need to set the response-header { responseType: 'blob'} in the request.

  2. You need to pass in the correct MIME-Type as you'are creating the blob-file. (f.e. application/octet-stream or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet).

component.ts

downloadFile(data: Response) {
  const blob = new Blob([data], { type: 'application/octet-stream' });
  const url= window.URL.createObjectURL(blob);
  window.open(url);
}
Sign up to request clarification or add additional context in comments.

2 Comments

How to get the file with specific file name? say "NameList.xlsx"?
When you use this, an sort of file is downloaded by the webbrowser. Though the file I'am sending from the API (which is correct), is not findable in there.
13

Add header { responseType: 'blob'}

Like this:

this.http.post<any>(apiEndpoint,request,{ responseType: 'blob'} )

1 Comment

I've set the HttpHeader as blob but still the same issue.
11

While using { responseType: 'blob'} as said by most answers here works, I'd suggest using responseType: 'arraybuffer' instead of blob with observe: 'response'. Your call would then look like this:

this.httpClient.get(resource, {
  headers: this.httpHeaders, // Any custom client side headers like Authorization
  observe: 'response',
  responseType: 'arraybuffer'
});

The advantage of this is two-fold:

  1. Arraybuffer is a generic stream of bytes and the Blob object can be created using either a blob or an arraybuffer, using the Content-Type
  2. observe: 'response' will also include the response headers that you set at the server in the parsed response.

I use this method to put the filename and the MIME Type of the arraybuffer in the Content-Disposition and Content-Type response headers and then use a generic download service at the client-side.

Also, I would suggest using a File object instead of just the Blob, which gives you the flexibility of giving it a filename like so:

public downloadFile(response: any, fileName?: string) {
    const blob = new Blob([response.body], { type: response.headers.get('content-type') });
    fileName = fileName || response.headers.get('content-disposition').split(';')[0];
    const file = new File([blob], fileName, { type: response.headers.get('content-type') });
    saveAs(file);
}

This will also solve the problem that @knbibin raised about using a custom filename.

5 Comments

This is working fine, but the fileName doesn't work
@suhas Can you tell me what is saveAs ?
@tech_geek It's a method from a node package called file-saver. You can simply do import { saveAs } from 'file-saver';
@SuhasBharadwaj I think it is not included in my angular that is why it is not being imported.
@tech_geek You can do npm install file-saver
6

Set response-header { responseType: 'blob'} in the request.

To download the excel, use the below function.

response - api response, fileName- excel name

downloadExcel(response, fileName) {
    // Doing it this way allows you to name the file
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(response);
    link.download = fileName;
    link.click();
  }

1 Comment

When you use this, an sort of file, which holds some xml data) is downloaded by the webbrowser. Though the file I'am sending from the API (which is correct), is not findable in there.
2

To download the file use the below code

downloadFile(data: Response) {
  const blob = new Blob([data], { type: 'application/octet-stream' });
  fs.saveAs(blob, fileName + '.xlsx');
}

3 Comments

According to the free dictionary "fs" has 195 definitions. Check it out here: acronyms.thefreedictionary.com/FS So, for the sake of clarity, please make the small, nevertheless an important, effort, to clarify what you mean by fs.saveAs(...). Just pasting code is not cool. This is actually an npm package (npmjs.com/package/file-saver) that allows you to save a stream to your file system from the browser, which answers the question posted above.
Its {import * as fs from 'file-saver';}, but I don't think the library still exists
You can still install it with: npm i file-saver, than it does work like a charm.
1

You need to Add { responseType : 'application/octet-stream'} in your get request as No need to call post method

{ responseType : 'application/octet-stream'}

And in .ts file

DownLoadExcel(){
    this.MprService.downLoadRFQInfoExcel(this.revisionId).subscribe(data =>{this.downloadFile(data)});
}
    
downloadFile(data: Blob) { 
    const contentType = 'application/vnd.openxmlformats-ficedocument.spreadsheetml.sheet'; 
    const blob = new Blob([data], { type: contentType });
    const url = window.URL.createObjectURL(blob);
    window.open(url);
}

Comments

0

If anyone wants only to download a file from assets, they can use this code:

<a href="./assets/files/file.xlsx" target="_blank"></a>

But you need to mention the location in angular.json

"architect": {
   "build": {
      "options": {
    "assets": [
                  "src/assets/files"
              ]
      }
   }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.