Set File Name while downloading via blob in Angular 5

50,829

Solution 1

You can set the download attribute to the filename you want, set the href to the object url, and then just call click

var blob = new Blob([data], { type: type.toString() });
var url = window.URL.createObjectURL(blob);
var anchor = document.createElement("a");
anchor.download = "myfile.txt";
anchor.href = url;
anchor.click();

Solution 2

If you want the exact filename of the uploaded file, set a custom header of the filename from backed API stream.

You can use it like this: my Excel API response headers:

content-disposition: inline;filename="salesReport.xls" 
content-type: application/octet-stream 
date: Wed, 22 Aug 2018 06:47:28 GMT 
expires: 0 
file-name: salesReport.xls 
pragma: no-cache 
transfer-encoding: chunked 
x-application-context: application:8080 
x-content-type-options: nosniff 
x-xss-protection: 1; mode=block

Service.ts

excel(data: any) {
  return this.httpClient.post(this.config.domain + 
  `/api/registration/excel/download`,data, {observe: 'response', responseType: 'blob'})
  .map((res) => {
      let data = {
                     image: new Blob([res.body], {type: res.headers.get('Content-Type')}),
                     filename: res.headers.get('File-Name')
                  }
    return data ;
  }).catch((err) => {
    return Observable.throw(err);
  });
}

Component.ts

excelDownload (data) {
   this.registration.excel(data).subscribe(
    (res) => {
     const element = document.createElement('a');
      element.href = URL.createObjectURL(res.image);
      element.download = res.filename;
      document.body.appendChild(element);
      element.click();
     this.toastr.success("Excel generated  successfully");
    },
  (error) =>{
     this.toastr.error('Data Not Found');
  });
}

Solution 3

Since some asked for a version with promise so you can use await und async:

Part 1: Get the Blob From the server:

  generateSapExcel(data: GenerateSapExport): Promise<HttpResponse<Blob>> {
    return this.http.post(`${this.pathprefix}/GenerateSapExcel`, data, { responseType: 'blob', observe: 'response' })
      .toPromise()
      .catch((error) => this.handleError(error));
  }

Part 2: Extract HttpResponse and deliver it to the user:

public downloadFile(data: HttpResponse<Blob>) {
    const contentDisposition = data.headers.get('content-disposition');
    const filename = this.getFilenameFromContentDisposition(contentDisposition);
    const blob = data.body;
    const url = window.URL.createObjectURL(blob);
    const anchor = document.createElement("a");
    anchor.download = filename;
    anchor.href = url;
    anchor.click();
  }

  private getFilenameFromContentDisposition(contentDisposition: string): string {
    const regex = /filename=(?<filename>[^,;]+);/g;
    const match = regex.exec(contentDisposition);
    const filename = match.groups.filename;
    return filename;
  }

Part 3: Combine both:

      const blobresponse = await this.dataService.generateSapExcel(dataToSend);
      this.downloadService.downloadFile(blobresponse);

Part 4: server:

        [HttpPost]
        [Route(nameof(GenerateSapExcel))]
        public async Task<FileStreamResult> GenerateSapExcel(GenerateSapExportDto dto)
        {
            Stream stream = await _sapKurepoService.GenerateSapExcel(dto);
            FileStreamResult result = File(stream, FileHelper.ContentypeExcel, "excel.xlsx");
            return result;
        }
Share:
50,829
Tanwer
Author by

Tanwer

Updated on March 28, 2020

Comments

  • Tanwer
    Tanwer about 4 years

    Below is my Typescript code to download file From API

    DownloadLM() {
    var ID= sessionStorage.getItem("UserID");
        return this.http.get(this.baseurl + 'api/DownloadFiles/DownloadLM/' + ID,
          {
            headers: {
              'Content-Type': 'application/json'
            },
            responseType: 'arraybuffer'
          }
        )
          .subscribe(respData => {
            this.downLoad(respData, this.type);
          }, error => {
          });
      }
    
      downLoad(data: any, type: string) {
        var blob = new Blob([data], { type: type.toString() });
        var url = window.URL.createObjectURL(blob);
        var pwa = window.open(url);
        if (!pwa || pwa.closed || typeof pwa.closed == 'undefined') {
          alert('Please disable your Pop-up blocker and try again.');
        }
      }
    

    This is Fine to download Excel File , but it gives a random name to file which I don't want , I want to set file name of my choice when downloading it ,

    Where can I set file name here ? any property of Blob ?

  • Tanwer
    Tanwer over 5 years
    Thanks , it works but I am also checking if pop up is blocked in browser or not , for that I wrote var pwa = anchor.click(); if (!pwa || pwa.closed || typeof pwa.closed == 'undefined') { alert('Please disable your Pop-up blocker and try again.'); } , but in your code it is not possible to check it as anchor.click() does not return a window
  • Sajeetharan
    Sajeetharan over 5 years
    you might need to do a hack there, upvote if this helped
  • Tanwer
    Tanwer over 5 years
    as it is happening in JS based framework and JS can be disabled , so taking caring of that is also required (pop up enable message), It partly helped not fully
  • Saravanan Sachi
    Saravanan Sachi over 5 years
    As it throws "Property 'download' does not exist on type HtmlAnchorElement" setting it as anchor.setAttribute("download", "<fileName>"); works
  • yonexbat
    yonexbat over 4 years
    res.headers.get('File-Name') helped. tnx.