How to Display blob (.pdf) in an AngularJS app
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>
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;
}
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>
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! :)
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) {
});