How to Display blob (.pdf) in an AngularJS app
Asked Answered
H

8

114

I have been trying to display pdf file which I am getting as a blob from a $http.post response. The pdf must be displayed within the app using <embed src> for example.

I came across a couple of stack posts but somehow my example doesn't seem to work.

JS:

According to this doc, I went on and tried...

$http.post('/postUrlHere',{myParams}).success(function (response) {
 var file = new Blob([response], {type: 'application/pdf'});
 var fileURL = URL.createObjectURL(file);
 $scope.content = fileURL;
});

Now from what I understand, fileURL creates a temporary URL that the blog can use as a reference.

HTML:

<embed src="{{content}}" width="200" height="200"></embed>

I am not sure how to handle this in Angular, the ideal situation would be to (1) assign it to a scope, (2) 'prepare/rebuild' the blob to a pdf (3) pass it to the HTML using <embed> because I want to display it within the app.

I have been researching for more than a day now but somehow I can't seem to understand how this works in Angular... And let's just assume the pdf viewer libraries out there weren't an option.

Hygiene answered 7/2, 2014 at 12:56 Comment(2)
Hi D'lo DeProjuicer, did you manage to get your problem of generating the PDF via angular fixed ?Laudian
@michael D'lo DeProjuicer What should be done for the same case in angular 2 ?Markle
C
222

First of all you need to set the responseType to arraybuffer. This is required if you want to create a blob of your data. See Sending_and_Receiving_Binary_Data. So your code will look like this:

$http.post('/postUrlHere',{myParams}, {responseType:'arraybuffer'})
  .success(function (response) {
       var file = new Blob([response], {type: 'application/pdf'});
       var fileURL = URL.createObjectURL(file);
});

The next part is, you need to use the $sce service to make angular trust your url. This can be done in this way:

$scope.content = $sce.trustAsResourceUrl(fileURL);

Do not forget to inject the $sce service.

If this is all done you can now embed your pdf:

<embed ng-src="{{content}}" style="width:200px;height:200px;"></embed>
Cogitate answered 12/2, 2014 at 15:22 Comment(12)
For me this did not work in Chrome (35.0.1916.114 m). Solved this by using <object> instead of <embed>: <object data="{{content}}" type="application/pdf"></object>Superbomb
Hi Michael and HoffZ, which js libraries did you include to have your PDF generated as I am experiencing problems about the file(PDF) being corrupt, it's generated but doesn't display in my case.Laudian
For me (AngularJS 1.25) I had to do: new Blob([response.data]Carmina
@HoffZ: I replaced the shortcut method $http.get with a full one, specifying the responseType field: { url: "http://127.0.0.1:8080/resources/jobs/af471106-2e71-4fe6-946c-cd1809c659e5/result/?key="+$scope.key, method: "GET", headers: { 'Accept': 'application/pdf' }, responseType: 'arraybuffer' } And it works :)Josefjosefa
Not sure why, since @Cogitate follows the specification. The only difference in my case: I use GET, not post. Source for my solution.Josefjosefa
Using ng-src didn't work with the embed tag when you change the src in the controller, so it loads first time but if you change the src because of a click for example then the src in the embed tag doesn't change. It is working fine with object tag thoughHin
hi, you solutions worked like charm...is there a way to remove PDF toolbar...i tried toolbar=0 navpanes=0 scrollbar =0 but not workingGirand
For me the only way to make it work was to create the blob with response.data instead of response, like this: var file = new Blob([response.data], {type: 'application/pdf'});Foucquet
or if you like it opened in new windows ` $window.open($sce.trustAsResourceUrl(fileURL)); `Bencher
@yosep-kim this does not work on IE because of URL object does not exist in IE: caniuse.com/#search=URLArtifice
Hi Friends, $http.get("xx.pdf", {responseType:'arraybuffer'}) .success(function (response) { var file = new Blob([(response)], {type: 'application/pdf'}); var fileURL = URL.createObjectURL(file); $scope.content=$sce.trustAsResourceUrl(fileURL); }); the above one is working for me. But, When i pass converted array byte like document to pdf array byte which is coming in response instead of xx.pdf file. The pdf is loaded with out content. i can see the page count as 15. Can you help me on this issue like how to show the content.Chaetopod
You can simply use {responseType:'arraybuffer'} when you make a request, and then location.href = fileURL.Mainmast
W
34

I use AngularJS v1.3.4

HTML:

<button ng-click="downloadPdf()" class="btn btn-primary">download PDF</button>

JS controller:

'use strict';
angular.module('xxxxxxxxApp')
    .controller('xxxxController', function ($scope, xxxxServicePDF) {
        $scope.downloadPdf = function () {
            var fileName = "test.pdf";
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            xxxxServicePDF.downloadPdf().then(function (result) {
                var file = new Blob([result.data], {type: 'application/pdf'});
                var fileURL = window.URL.createObjectURL(file);
                a.href = fileURL;
                a.download = fileName;
                a.click();
            });
        };
});

JS services:

angular.module('xxxxxxxxApp')
    .factory('xxxxServicePDF', function ($http) {
        return {
            downloadPdf: function () {
            return $http.get('api/downloadPDF', { responseType: 'arraybuffer' }).then(function (response) {
                return response;
            });
        }
    };
});

Java REST Web Services - Spring MVC:

@RequestMapping(value = "/downloadPDF", method = RequestMethod.GET, produces = "application/pdf")
    public ResponseEntity<byte[]> getPDF() {
        FileInputStream fileStream;
        try {
            fileStream = new FileInputStream(new File("C:\\xxxxx\\xxxxxx\\test.pdf"));
            byte[] contents = IOUtils.toByteArray(fileStream);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/pdf"));
            String filename = "test.pdf";
            headers.setContentDispositionFormData(filename, filename);
            ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
            return response;
        } catch (FileNotFoundException e) {
           System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
        return null;
    }
Wicklund answered 22/5, 2015 at 19:54 Comment(9)
which version of safari? window.URL is good in safari 9 and after: caniuse.com/#search=createObjectURLShantelleshantha
I tested and valided on my MacBook pro and safari 9.0.2.Shantelleshantha
Same, macBook el captain. window.URL.createObjectURL(file); i dont where is the problem but code doesnt work. May be i do something wrong. Any thank you. I haven't time to check what it not working and use FileSaver.jsExegetics
if your application is online, post your URL please? have you the same Back-End?Shantelleshantha
download attribute is not supported in safari. caniuse.com/#search=downloadLiteralminded
@Biswanath, which version of safari? window.URL is good in safari 9 and after: caniuse.com/#search=createObjectURLShantelleshantha
@sgrillon: I was mentioning the download attribute caniuse.com/#search=downloadLiteralminded
in api/downloadPDF - > which is containing only bytearray. if bytearray, it is not working for me. if i give local file as x.pdf. then my pdf is rendering on page. i dont want to download. i need to show the pdf file in the page itself using angular. can you give your solutions for showing pdf file in viewChaetopod
if you put "application/pdf" in a header, your pdf is open in tab browser. in java => headers.setContentType(MediaType.parseMediaType("application/pdf"));Shantelleshantha
R
23

michael's suggestions works like a charm for me :) If you replace $http.post with $http.get, remember that the .get method accepts 2 parameters instead of 3... this is where is wasted my time... ;)

controller:

$http.get('/getdoc/' + $stateParams.id,     
{responseType:'arraybuffer'})
  .success(function (response) {
     var file = new Blob([(response)], {type: 'application/pdf'});
     var fileURL = URL.createObjectURL(file);
     $scope.content = $sce.trustAsResourceUrl(fileURL);
});

view:

<object ng-show="content" data="{{content}}" type="application/pdf" style="width: 100%; height: 400px;"></object>
Rottenstone answered 11/6, 2015 at 14:3 Comment(3)
responseType:'arraybuffer', just saved me a couple of sleeping hours! +1Riccio
how to trigger the save instead to print it in html?Exegetics
thank you, this saved me a couple of hours, you can also replace $scope.content = $sce.trustAsResourceUrl(fileURL); with $window.open(fileURL, '_self', ''); and open the file on fullscreen.Mccue
P
10

I faced difficulties using "window.URL" with Opera Browser as it would result to "undefined". Also, with window.URL, the PDF document never opened in Internet Explorer and Microsoft Edge (it would remain waiting forever). I came up with the following solution that works in IE, Edge, Firefox, Chrome and Opera (have not tested with Safari):

$http.post(postUrl, data, {responseType: 'arraybuffer'})
.success(success).error(failed);

function success(data) {
   openPDF(data.data, "myPDFdoc.pdf");
};

function failed(error) {...};

function openPDF(resData, fileName) {
    var ieEDGE = navigator.userAgent.match(/Edge/g);
    var ie = navigator.userAgent.match(/.NET/g); // IE 11+
    var oldIE = navigator.userAgent.match(/MSIE/g); 

    var blob = new window.Blob([resData], { type: 'application/pdf' });

    if (ie || oldIE || ieEDGE) {
       window.navigator.msSaveBlob(blob, fileName);
    }
    else {
       var reader = new window.FileReader();
       reader.onloadend = function () {
          window.location.href = reader.result;
       };
       reader.readAsDataURL(blob);
    }
}

Let me know if it helped! :)

Perpend answered 8/1, 2016 at 21:41 Comment(3)
This approach does not open the PDF document in the browser window in IE but prompts the user to download it. Is there any work around this?Zannini
The above code is to download the PDF file and let your default PDF Reader app take over to open it. It even works well on mobile devices. Reason is, while I was able to open the PDF on some browsers, I could not open it on other ones. So I thought it was best to have a solution that would run on all browsers (including mobile browsers) to download the PDF file.Perpend
You can use the following code to view the PDF in a new tab: window.open(reader.result, '_blank');Roommate
M
6

Adding responseType to the request that is made from angular is indeed the solution, but for me it didn't work until I've set responseType to blob, not to arrayBuffer. The code is self explanatory:

    $http({
            method : 'GET',
            url : 'api/paperAttachments/download/' + id,
            responseType: "blob"
        }).then(function successCallback(response) {
            console.log(response);
             var blob = new Blob([response.data]);
             FileSaver.saveAs(blob, getFileNameFromHttpResponse(response));
        }, function errorCallback(response) {   
        });
Marlite answered 27/3, 2017 at 8:20 Comment(1)
actually, with 'blob' type it is possible to write shorter: FileSaver.saveAs(response.data, getFileNameFromHttpResponse(response)); No need to create BlobAeon
A
1

Most recent answer (for Angular 8+):

this.http.post("your-url",params,{responseType:'arraybuffer' as 'json'}).subscribe(
  (res) => {
    this.showpdf(res);
  }
)};

public Content:SafeResourceUrl;
showpdf(response:ArrayBuffer) {
  var file = new Blob([response], {type: 'application/pdf'});
  var fileURL = URL.createObjectURL(file);
  this.Content = this.sanitizer.bypassSecurityTrustResourceUrl(fileURL);
}

  HTML :

  <embed [src]="Content" style="width:200px;height:200px;" type="application/pdf" />
Arsenault answered 10/6, 2020 at 11:29 Comment(0)
F
0

I have struggled for the past couple of days trying to download pdfs and images,all I was able to download was simple text files.

Most of the questions have the same components, but it took a while to figure out the right order to make it work.

Thank you @Nikolay Melnikov, your comment/reply to this question was what made it work.

In a nutshell, here is my AngularJS Service backend call:

  getDownloadUrl(fileID){
    //
    //Get the download url of the file
    let fullPath = this.paths.downloadServerURL + fileId;
    //
    // return the file as arraybuffer 
    return this.$http.get(fullPath, {
      headers: {
        'Authorization': 'Bearer ' + this.sessionService.getToken()
      },
      responseType: 'arraybuffer'
    });
  }

From my controller:

downloadFile(){
   myService.getDownloadUrl(idOfTheFile).then( (response) => {
      //Create a new blob object
      let myBlobObject=new Blob([response.data],{ type:'application/pdf'});

      //Ideally the mime type can change based on the file extension
      //let myBlobObject=new Blob([response.data],{ type: mimeType});

      var url = window.URL || window.webkitURL
      var fileURL = url.createObjectURL(myBlobObject);
      var downloadLink = angular.element('<a></a>');
      downloadLink.attr('href',fileURL);
      downloadLink.attr('download',this.myFilesObj[documentId].name);
      downloadLink.attr('target','_self');
      downloadLink[0].click();//call click function
      url.revokeObjectURL(fileURL);//revoke the object from URL
    });
}
Fidellas answered 25/1, 2017 at 6:5 Comment(0)
G
-2

A suggestion of code that I just used in my project using AngularJS v1.7.2

$http.get('LabelsPDF?ids=' + ids, { responseType: 'arraybuffer' })
            .then(function (response) {
                var file = new Blob([response.data], { type: 'application/pdf' });
                var fileURL = URL.createObjectURL(file);
                $scope.ContentPDF = $sce.trustAsResourceUrl(fileURL);
            });

<embed ng-src="{{ContentPDF}}" type="application/pdf" class="col-xs-12" style="height:100px; text-align:center;" />
Garofalo answered 2/11, 2018 at 4:34 Comment(1)
please add some brief too.Idaho

© 2022 - 2024 — McMap. All rights reserved.