I've created an application in Angular JS for downloading an Excel workbook through $http post.
In the below code I'm passing the information in the form of JSON , and send it to the server REST web service (java) through an angular $http post. The web service uses the information from the JSON and produces an Excel workbook. In the response within the success body of $http post, I'm getting binary data within that data variable, but don't know how to convert it and download as an Excel file.
Can anyone please tell me some solution for this for converting the binary to Excel file and download?
My code is as given below:
$http({
url: 'myweb.com/myrestService',
method: "POST",
data: json, //this is your json data string
headers: {
'Content-type': 'application/json'
}
}).success(function (data, status, headers, config) {
// Here i'm getting excel sheet binary datas in 'data'
}).error(function (data, status, headers, config) {
});
I created a service that will do this for you.
Pass in a standard $http
object, and add some extra parameters.
1) A "type" parameter. Specifying the type of file you're retrieving. Defaults to: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
2) A "fileName" parameter. This is required, and should include the extension.
Example:
httpDownloader({
method : 'POST',
url : '--- enter the url that returns a file here ---',
data : ifYouHaveDataEnterItHere,
type : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // this is the default
fileName : 'YourFileName.xlsx'
}).then(res => {}).catch(e => {});
That's all you need. The file will be downloaded to the user's device without a popup.
Here's the git repo: https://github.com/stephengardner/ngHttpDownloader
Answer No 5 worked for me ,Suggestion to developer who are facing similar issue.
//////////////////////////////////////////////////////////
//Server side
//////////////////////////////////////////////////////////
imports ***
public class AgentExcelBuilder extends AbstractExcelView {
protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
//poi code goes here ....
response.setHeader("Cache-Control","must-revalidate");
response.setHeader("Pragma", "public");
response.setHeader("Content-Transfer-Encoding","binary");
response.setHeader("Content-disposition", "attachment; filename=test.xls");
OutputStream output = response.getOutputStream();
workbook.write(output);
System.out.println(workbook.getActiveSheetIndex());
System.out.println(workbook.getNumberOfSheets());
System.out.println(workbook.getNumberOfNames());
output.flush();
output.close();
}//method buildExcelDocument ENDS
//service.js at angular JS code
function getAgentInfoExcel(workgroup,callback){
$http({
url: CONTEXT_PATH+'/rest/getADInfoExcel',
method: "POST",
data: workgroup, //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.ms-excel"});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}).error(function (data, status, headers, config) {
console.log('Failed to download Excel')
});
}
////////////////////////////////in .html
<div class="form-group">`enter code here`
<a href="javascript:void(0)" class="fa fa-file-excel-o"
ng-click="exportToExcel();"> Agent Export</a>
</div>
Worked for me -
$scope.downloadFile = function () {
Resource.downloadFile().then(function (response) {
var blob = new Blob([response.data], { type: "application/pdf" });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
},
function (error) {
debugger;
});
};
Which calls the following from my resource factory-
downloadFile: function () {
var downloadRequst = {
method: 'GET',
url: 'http://localhost/api/downloadFile?fileId=dfckn4niudsifdh.pdf',
headers: {
'Content-Type': "application/pdf",
'Accept': "application/pdf"
},
responseType: 'arraybuffer'
}
return $http(downloadRequst);
}
Make sure your API sets the header content type too -
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
I was facing this same problem. Let me tell you how I solved it and achieved everything you all seem to be wanting.
Requirements:
In my service, (I'm using Asp.net Web API), I have a controller returning an "HttpResponseMessage". I add a "StreamContent" to the response.Content field, set the headers to "application/octet-stream" and add the data as an attachment. I even give it a name "myAwesomeFile.xlsx"
response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(memStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "myAwesomeFile.xlsx" };
Now here's the trick ;)
I am storing the base URL in a text file that I read into a variable in an Angular Value called "apiRoot". I do this by declaring it and then setting it on the "run" function of the Module, like so:
app.value('apiRoot', { url: '' });
app.run(function ($http, apiRoot) {
$http.get('/api.txt').success(function (data) {
apiRoot.url = data;
});
});
That way I can set the URL in a text file on the server and not worry about "blowing it away" in an upload. (You can always change it later for security reasons - but this takes the frustration out of development ;) )
And NOW the magic:
All I'm doing is creating a link with a URL that directly hits my service endpoint and target's a "_blank".
<a ng-href="{{vm.getFileHref(FileId)}}" target="_blank" class="btn btn-default"> Excel File</a>
the secret sauce is the function that sets the href. You ready for this?
vm.getFileHref = function (Id) {
return apiRoot.url + "/datafiles/excel/" + Id;
}
Yep, that's it. ;)
Even in a situation where you are iterating over many records that have files to download, you simply feed the Id to the function and the function generates the url to the service endpoint that delivers the file.
Hope this helps!
You could as well take an alternative approach -- you don't have to use $http, you don't need any extra libraries, and it ought to work in any browser.
Just place an invisible form on your page.
<form name="downloadForm" action="/MyApp/MyFiles/Download" method="post" target="_self">
<input type="hidden" name="value1" value="{{ctrl.value1}}" />
<input type="hidden" name="value2" value="{{ctrl.value2}}" />
</form>
And place this code in your angular controller.
ctrl.value1 = 'some value 1';
ctrl.value2 = 'some value 2';
$timeout(function () {
$window.document.forms['downloadForm'].submit();
});
This code will post your data to /MyApp/MyFiles/Download and you'll receive a file in your Downloads folder.
It works with Internet Explorer 10.
If a conventional HTML form doesn't let you post your complex object, then you have two options:
1. Stringify your object and put it into one of the form fields as a string.
<input type="hidden" name="myObjJson" value="{{ctrl.myObj | json:0}}" />
2. Consider HTML JSON forms: https://www.w3.org/TR/html-json-forms/
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);
}
}
There is no way (to my knowledge) to trigger the download window in your browser from Javascript. The only way to do it is to redirect the browser to a url that streams the file to the browser.
If you can modify your REST service, you might be able to solve it by changing so the POST request doesn't respond with the binary file, but with a url to that file. That'll get you the url in Javascript instead of the binary data, and you can redirect the browser to that url, which should prompt the download without leaving the original page.
This is how you do it:
$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
Source: Stackoverflow.com