How to download excel/Zip files in Angular 4

13,621

Try this:

downloadExcel() {

  const type = 'application/vnd.ms-excel';
  const filename = 'file.xls';
  const options = new RequestOptions({
            responseType: ResponseContentType.Blob,
            headers: new Headers({ 'Accept': type })
        });

  this.http.get('http://10.2.2.109/Download/exportExcel', options)
           .catch(errorResponse => Observable.throw(errorResponse.json()))
           .map((response) => { 
                 if (response instanceof Response) {
                    return response.blob();
                 }
                 return response;
            })
           .subscribe(data => saveAs(data, filename),
                      error => console.log(error)); // implement your error handling here

}

The key points are responseType: ResponseContentType.Blob on the RequestOptions and response.blob() when getting back the response.

In general, it's not recommended to access the _body property of the response like this: response._body, but instead you should call the relevant method to get the body content based on its type (like response.blob(), response.json(), etc)

Share:
13,621
Binish Prabhakar
Author by

Binish Prabhakar

Senior Software Engineer, passionate about JavaScript and all things Web, also full stalk development.

Updated on June 05, 2022

Comments

  • Binish Prabhakar
    Binish Prabhakar almost 2 years

    I am using angular 4 as frond end and lumen 5.4 as back end.

    My requirement is to export some data as excel and zip file.

    Using import { saveAs } from 'file-saver/FileSaver'; package for file download.

    Angular 4 Code:

    downloadExcel() {
    
    const type = 'application/vnd.ms-excel';
    const headers = { headers: new Headers({ 'Accept': type }) };
    const filename = 'file.xls';
    
    this.http.get('http://10.2.2.109/Download/exportExcel', headers)
      .toPromise()
      .then(response => this.saveToFileSystem(response, type, filename));
    
    return false;
    
    
    }
    
    
    
    private saveToFileSystem(response, __type, filename) {
        const contentDispositionHeader: string = response.headers.get('Content-Disposition');
    
    if (contentDispositionHeader !== null) {
      const parts: string[] = contentDispositionHeader.split(';');
      //const filename = parts[1].split('=')[1];
      const blob = new Blob([response._body], { type: __type });
      saveAs(blob, filename);
    } else {
      alert('Cant download.....');
      // handling download condition if content disposition is empty
      const blob = new Blob([response._body], { type: __type });
      saveAs(blob, filename);
    }
    
    
    }
    

    Lumen Code

    public function exportExcel(Request $request) {
            $file = storage_path();
            $file_name = 'book1.xls';
            $headers = [
                'Content-type' => 'application/vnd.ms-excel',
                'Content-Disposition' => 'attachment;filename="' . $file_name,
                'X-Filename' => $file_name,
                'Content-Transfer-Encoding' => 'binary',
                'Content-Length' => filesize($file . '/' . $file_name),
                'Cache-Control' => 'max-age=0',
                'Cache-Control' => 'max-age=1',
                'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
                'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
                'Cache-Control' => 'cache, must-revalidate',
                'Pragma' => 'public',
                'Set-Cookie' => 'fileDownload=true; path=/',
                'Access-Control-Expose-Headers' => 'Content-Length,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma'
            ];
    
            return response()->download($file . '/' . $file_name, $file_name, $headers);
        }
    

    Issues

    1. const contentDispositionHeader: string = response.headers.get('Content-Disposition'); seems always empty.
    2. We cant open downloaded file, shows corrupted message.
    3. It working for text file download

    Please help me to resolve this issue. OR specify any other working code//package for angular

  • Binish Prabhakar
    Binish Prabhakar over 6 years
    Thank you :) One more doubt, how to modify the service to access both json data and blob data. The condition is we are passing authorization headers along with the request, if authorization fails or unable to generate excel API will return json. In that condition how we can change service to access response type to handle blob as well as json data.
  • Andrei Matracaru
    Andrei Matracaru over 6 years
    See my updated code sample for a possible solution. I added a catch operator that would catch any HTTP error responses (so basically HTTP error codes > 400), and would then extract the json out of the response, creating a new Observable with that content. Then, in the map you would have to check if the input is an instance of Response to extract the blob (the happy case), or if not just pass the content on (the error case). Bear in mind this is not tested, so I am not sure it will work. However, at least it should give you some ideas I hope :)
  • Binish Prabhakar
    Binish Prabhakar over 6 years
    Except blob data all other conditions we are returning json data with status code 200. In this case how we can handle.
  • Andrei Matracaru
    Andrei Matracaru over 6 years
    Well, you shouldn't :). You should use HTTP codes for error conditions, such as 401 for unauthorized or 400 for bad request. Otherwise, I don't really see how you could distinguish between a successful response and an error. I guess you could try in the map function response.blob() inside a try block, and then response.json() in a catch block...but it's pretty ugly tbh
  • Binish Prabhakar
    Binish Prabhakar over 6 years
    As I am new to angular please advise me, for the above mentioned scenario what is the genius method to wrote code.
  • Binish Prabhakar
    Binish Prabhakar over 6 years
    How to catch error messages. If the http status is not 200. Right now we are using catch and subscribe response that are not able to get the response body. Only getting error. Statustext
  • Sanjay Tiwari
    Sanjay Tiwari almost 5 years
    Works! for me but i have change responseType: 'blob', this works for me of both files .csv & .xlsx type files. Please find my code.... return this.http.get(url, { headers: headers, responseType: 'blob', observe: 'response' });