19

I have problem very similar to this PDF Blob - Pop up window not showing content, but I am using Angular 2. The response on question was to set responseType to arrayBuffer, but it not works in Angular 2, the error is the reponseType does not exist in type RequestOptionsArgs. I also tried to extend it by BrowserXhr, but still not work (https://github.com/angular/http/issues/83).

My code is:

createPDF(customerServiceId: string) {
   console.log("Sending GET on " + this.getPDFUrl + "/" + customerServiceId);

   this._http.get(this.getPDFUrl + '/' + customerServiceId).subscribe(
       (data) => {
            this.handleResponse(data);
         });
}

And the handleResponse method:

handleResponse(data: any) {
     console.log("[Receipt service] GET PDF byte array " + JSON.stringify(data));

     var file = new Blob([data._body], { type: 'application/pdf' });            
     var fileURL = URL.createObjectURL(file);
     window.open(fileURL);
 }

I also tried to saveAs method from FileSaver.js, but it is the same problem, pdf opens, but the content is not displayed. Thanks

Community
  • 1
  • 1
Loutocký
  • 822
  • 2
  • 15
  • 28

5 Answers5

67

I had a lot of problems with downloading and showing content of PDF, I probably wasted a day or two to fix it, so I'll post working example of how to successfully download PDF or open it in new tab:

myService.ts

downloadPDF(): any {
        return this._http.get(url, { responseType: ResponseContentType.Blob }).map(
        (res) => {
            return new Blob([res.blob()], { type: 'application/pdf' })
        }
}

myComponent.ts

this.myService.downloadPDF().subscribe(
        (res) => {
            saveAs(res, "myPDF.pdf"); //if you want to save it - you need file-saver for this : https://www.npmjs.com/package/file-saver

        var fileURL = URL.createObjectURL(res);
        window.open(fileURL); / if you want to open it in new tab

        }
    );

NOTE

It is also worth mentioning that if you are extending Http class to add headers to all your requests or something like that, it can also create problems for downloading PDF because you will override RequestOptions, which is where we add responseType: ResponseContentType.Blob and this will get you The request body isn't either a blob or an array buffer error.

Stefan Svrkota
  • 48,787
  • 9
  • 98
  • 87
  • 1
    when I open pdf file with window.open(url) its stuck with popup blocker by the browser. Also can we also rename the file. any solution. – Amit Jamwal Jan 06 '17 at 14:17
  • 1
    @PeterAlbert You're very welcome! To be honest, I didn't think anyone else would stumble upon the same problem. :) – Stefan Svrkota Mar 28 '17 at 15:06
  • I have the exact same problem: Because I set a "Range" header, the "responseType: ResponseContentType.Blob" seems to be ignored and "The request body isn't either a blob or an array buffer" is thrown (why request and not response??). Do you know how to avoid this? – Rico Suter Apr 06 '17 at 06:58
  • @RicoSuter If you are setting "Range" header after you set `responseType`, your `responseType` will be overwritten. You can set both simultaneously in order to avoid overwriting. – Stefan Svrkota Apr 06 '17 at 08:16
  • I use a plain object, so this shouldn't be a problem: let options_ = { body: content_, method: "get", responseType: ResponseContentType.Blob, headers: new Headers({ "Range": range, "Content-Type": "application/json; charset=UTF-8" }) }; return this.http.request(url_, options_); – Rico Suter Apr 06 '17 at 15:41
  • 1
    The res.blob() was what I was missing. Most examples I have seen just do [res] – kelsmj May 30 '17 at 17:28
  • 1
    This worked for me perfectly, I was dealing with and image, not a pdf – Ernest Jun 23 '17 at 13:05
  • 1
    I have a question about how to deal with the case when `http` is extended to add a JWT to every request. Are you willing to help? Here is [the link](https://stackoverflow.com/questions/44813133/pdf-from-rest-api-not-loading-into-angular-2-app). – CodeMed Jun 28 '17 at 22:03
  • @CodeMed I am willing to try. :) You can create two methods for get requests in your `CustomHttp`, for example `get()` and `getBlob()` and you can use `getBlob()` for getting PDF and other files and regular `get()` for regular requests. – Stefan Svrkota Jun 28 '17 at 22:58
  • 1
    Legend, I was getting error "The request body isn't either a blob or an array buffer", this solution has resolved it all, thanks! – Ka Tech Feb 16 '18 at 03:38
  • I'm not getting any result here. Drilling down in the returned blob, I see an exception: angular 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.remoteFunction – Jnr Mar 12 '18 at 19:57
  • This is actually downloading the pdf for me. The 'fileUrl' is actually "blob:http://localhost:50293/b8ec01fd-4cc2-4f4a-9001-594f8ae9441d"; without a .pdf extension – int-i Mar 12 '18 at 20:31
  • I tried the same in angular 5 with observable subscribe, getting an error while rendering the pdf. – MPPNBD May 09 '18 at 18:07
  • https://stackoverflow.com/questions/63187758/issue-while-printing-pdf-files-from-blob-agnular can you help on this? – Sunil Garg Aug 01 '20 at 07:24
4

ANGULAR 5

I had the same problem which I lost few days on that.

Here my answer may help others, which helped to render pdf.

For me even though if i mention as responseType : 'arraybuffer', it was unable to take it.

For that you need to mention as responseType : 'arraybuffer' as 'json'.(Reference)

Working code

downloadPDF(): any {
    return this._http.get(url, {  responseType: 'blob' as 'json' }).subscribe((res) => {
        var file = new Blob([res], { type: 'application/pdf' });            
        var fileURL = URL.createObjectURL(file);
        window.open(fileURL);
    }
}

Referred from the below link

https://github.com/angular/angular/issues/18586

MPPNBD
  • 1,566
  • 4
  • 20
  • 36
0

Amit, You can rename the filename by adding a variable to the end of the string so saveAs(res, "myPDF.pdf");

Becomes

saveAs(res, "myPDF_"+someVariable+".pdf");

where someVariable might be a counter or my personal favorite a date time string.

Jaap
  • 81,064
  • 34
  • 182
  • 193
Ken
  • 423
  • 6
  • 13
  • Sorry about the Answer, I thought I was adding it as a comment to Amit's question. – Ken Jan 10 '17 at 04:04
  • https://stackoverflow.com/questions/63187758/issue-while-printing-pdf-files-from-blob-agnular can you help on this? – Sunil Garg Aug 01 '20 at 07:25
0

This worked for me

 var req = this.getPreviewPDFRequest(fd);
        this.postData(environment.previewPDFRFR, req).then(res => {
          res.blob().then(blob => {
            console.clear();
            console.log(req);
            console.log(JSON.stringify(req));
            const fileURL = URL.createObjectURL(blob);
            window.open(fileURL, '', 'height=650,width=840');
          })
        });
0

Server side (Java/Jetty) : REST service that returns a File Response The File Response itself will automatically be parsed into a pdf blob file by Jetty (because of the annotation @Produces("application/pdf") ), in other to be send to and read by the web client

    @GET
    @Path("/download-pdf/{id}")
    @Produces("application/pdf")
    public Response downloadPDF(@ApiParam(value = "Id of the report record")
                            @PathParam("id") Long id) {
        ResponseBuilder response = null;
        try {
            PDFReportService service = new PDFReportService();
            File reportFile = service.getPDFReportFile(id);

            response = Response.ok((Object) reportFile);  
            response.header("Content-Disposition","attachment; filename="+reportFile.getName());  
            return response.build();
        } catch (DomainException e) {
            response = Response.serverError().entity("server.error");
        }
        return response.build();
    }

Client side code (angular 2) : grab the blob and print it in a new browser tab

The key is to insure that you read the request reponse as a blob (as the server returned a blob; in my case)

Now, I tried so hard but I finally figured out that Angular 2 has not implemented any function to handle blob responses (neither res['_body'], nor res.blob() worked for me)

So I found no other workaround than using JQuery ajax to perform that file blob request, like following:

public downloadPDFFile() {
    let fileURL = serverURL+"/download-pdf/"+id;
    let userToken: string = your_token;

    showWaitingLoader();

    $.ajax({
        url: fileURL,
        cache: false,
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Basic " + userToken
        },
        xhrFields: {
            responseType: 'blob' //Most important : configure the response type as a blob
        },
        success: function(blobFile) {
            const url = window.URL.createObjectURL(blobFile);
            window.open(url);
            stopWaitingLoader();
        },
        error: function(e){
            console.log("DOWNLOAD ERROR :", e);
        }
    });
}
BryZe NtZa
  • 31
  • 1
  • 4