Angular 6 Downloading file from rest api

I resolved it as follows:

// header.component.ts
this.downloadService.getPdf().subscribe((data) => {

  this.blob = new Blob([data], {type: 'application/pdf'});

  var downloadURL = window.URL.createObjectURL(data);
  var link = document.createElement('a');
  link.href = downloadURL;
  link.download = "help.pdf";
  link.click();

});



//download.service.ts
getPdf() {

  const httpOptions = {
    responseType: 'blob' as 'json')
  };

  return this.http.get(`${this.BASE_URL}/help/pdf`, httpOptions);
}

I solved the issue in this way (please note that I have merged multiple solutions found on stack overflow, but I cannot find the references. Feel free to add them in the comments).

In My service I have:

public getPDF(): Observable<Blob> {   
//const options = { responseType: 'blob' }; there is no use of this
    let uri = '/my/uri';
    // this.http refers to HttpClient. Note here that you cannot use the generic get<Blob> as it does not compile: instead you "choose" the appropriate API in this way.
    return this.http.get(uri, { responseType: 'blob' });
}

In the component, I have (this is the part merged from multiple answers):

public showPDF(fileName: string): void {
    this.myService.getPDF()
        .subscribe(x => {
            // It is necessary to create a new blob object with mime-type explicitly set
            // otherwise only Chrome works like it should
            var newBlob = new Blob([x], { type: "application/pdf" });
            
            // IE doesn't allow using a blob object directly as link href
            // instead it is necessary to use msSaveOrOpenBlob
            if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                window.navigator.msSaveOrOpenBlob(newBlob, fileName);
                return;
            }
            
            // For other browsers: 
            // Create a link pointing to the ObjectURL containing the blob.
            const data = window.URL.createObjectURL(newBlob);
            
            var link = document.createElement('a');
            link.href = data;
            link.download = fileName;
            // this is necessary as link.click() does not work on the latest firefox
            link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
            
            setTimeout(function () {
                // For Firefox it is necessary to delay revoking the ObjectURL
                window.URL.revokeObjectURL(data);
                link.remove();
            }, 100);
        });
}

The code above works in IE, Edge, Chrome and Firefox. However, I don't really like it, as my component is pulluted with browser specific stuff which will surely change over time.


For Angular 12+, I came up with something like this:

this.ApiService
    .getFileFromApi()
    .pipe(take(1))
    .subscribe((response) => {
        const downloadLink = document.createElement('a');
        downloadLink.href = URL.createObjectURL(new Blob([response.body], { type: response.body.type }));

        const contentDisposition = response.headers.get('content-disposition');
        const fileName = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();
        downloadLink.download = fileName;
        downloadLink.click();
    });

The subscribe is on a simple get() with the Angular HttpClient.

// api-service.ts

getFileFromApi(url: string): Observable<HttpResponse<Blob>> {
  return this.httpClient.get<Blob>(this.baseApiUrl + url, { observe: 'response', responseType: 'blob' as 'json'});
}