AngularJS $http-post - convert binary to excel file and download
Just noticed you can't use it because of IE8/9 but I'll push submit anyway... maybe someone finds it useful
This can actually be done through the browser, using blob
. Notice the responseType
and the code in the success
promise.
$http({ url: 'your/webservice', method: "POST", data: json, //this is your json data string headers: { 'Content-type': 'application/json' }, responseType: 'arraybuffer'}).success(function (data, status, headers, config) { var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}); var objectUrl = URL.createObjectURL(blob); window.open(objectUrl);}).error(function (data, status, headers, config) { //upload failed});
There are some problems with it though like:
- It doesn't support IE 8 and 9:
- It opens a pop up window to open the
objectUrl
which people might have blocked - Generates weird filenames
It did work!
The server side code in PHP I tested this with looks like this. I'm sure you can set similar headers in Java:
$file = "file.xlsx";header('Content-disposition: attachment; filename='.$file);header('Content-Length: ' . filesize($file));header('Content-Transfer-Encoding: binary');header('Cache-Control: must-revalidate');header('Pragma: public');echo json_encode(readfile($file));
Edit 20.04.2016
Browsers are making it harder to save data this way. One good option is to use filesaver.js. It provides a cross browser implementation for saveAs
, and it should replace some of the code in the success
promise above.
This is how you do it:
- Forget IE8/IE9, it is not worth the effort and does not pay the money back.
- You need to use the right HTTP header,use Accept to 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' and also you need to put responseType to 'arraybuffer'(ArrayBuffer but set with lowercase).
- HTML5 saveAs is used to save the actual data to your wanted format. Note it will still work without adding type in this case.
$http({ url: 'your/webservice', method: 'POST', responseType: 'arraybuffer', data: json, //this is your json data string headers: { 'Content-type': 'application/json', 'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }}).success(function(data){ var blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); saveAs(blob, 'File_Name_With_Some_Unique_Id_Time' + '.xlsx');}).error(function(){ //Some error log});
Tip! Don't mix " and ', stick to always use ', in a professional environment you will have to pass js validation for example jshint, same goes for using === and not ==, and so on, but that is another topic :)
I would put the save excel in another service, so you have clean structure and the post is in a proper service of its own. I can make a JS fiddle for you, if you don't get my example working. Then I would also need some json data from you that you use for a full example.
Happy coding.. Eduardo
Download the server response as an array buffer. Store it as a Blob using the content type from the server (which should be application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
):
var httpPromise = this.$http.post(server, postData, { responseType: 'arraybuffer' });httpPromise.then(response => this.save(new Blob([response.data], { type: response.headers('Content-Type') }), fileName));
Save the blob to the user's device:
save(blob, fileName) { if (window.navigator.msSaveOrOpenBlob) { // For IE: navigator.msSaveBlob(blob, fileName); } else { // For other browsers: var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = fileName; link.click(); window.URL.revokeObjectURL(link.href); }}