how to RECEIVE downloadable file from server in AngularJS? - angularjs

I am sending a downloadable file from backend to AngularJS. Whenever a GET request (with some data as parameters) is made to the "/report" url, the server sends a file that I want to receive in AngularJS. Ideally, a browser should prompt user for saving/opening a file that server sends. So far I have done this:
$scope.getReport = function () {
console.log("getReport");
var report_url = '/report';
var some_data = "asdf";
$http({method:'GET', url:report_url, data=some_data})
.success(function(data) {
});
};
Now I am unable to figure out how to get the file that server sent me.

I created this fiddle for you http://jsfiddle.net/xMdQV/
Instead of making a get request and waiting for the server to return a file that you want to download
you could replace someData with your some_data
Tested on Chrome, Firefox and IE9.

Related

Rename a file which comes from a copy/paste (on server side or front side)

In a textarea, people can paste pictures. I handle that with AngularJS, the ng-paste directive and this piece of code
ctrl.handlePaste = function(event) {
if(event.clipboardData.items.length > 0) {
for(var i = 0; i < event.clipboardData.items.length; i++) {
var item = event.clipboardData.items[i]; // type: DataTransferItem
if (item.type.indexOf("image") != -1) {
file = item.getAsFile(); // type: File
// it's then stored in a array and will be sent to the server
break;
}
}
}
}
Then I send it to my Flask server (Python 2.7) and it is then sent by emails or pushed via API to another service.
On server side I've checked the type and it's a Flask FileStorage.
My problem is: this file is automatically named "image.png" (I'm using Chrome) and I cant find a way to change this name during the process.
I'm ok with changing it on front side (my favourite option), I'm ok on server side too.
If the code uses the formData API, the filename is the third (optional) argument to the formdata.append method. If the code sends the image as a blob with XHR send the filename can be sent in a query param or a Content-Disposition header.

Downloading an Excel file causes it to corrupt

I have a simple service on Angular 2 and Typescript that requests Excel files to a server and then opens a download file dialogue for the user. However, as it is currently, the file becomes corrupt when downloaded.
When downloaded, it opens fine in OpenOffice and derivates, but throws a "File is Corrupt" error on Microsoft Excel, and asks if the user wants to recover as much as it can.
When Excel is prompted to recover the file, it does so successfully, and the recovered Excel has all rows and data that is expected for the Excel file. Comparing the recovered file against opening the file in OpenOffice and derivates evidence no outstanding differences.
The concrete Excel I am trying to download is generated with Apache POI in a microservice, then passed to the main backend and finally served to the frontend for the user to download. Both the backend and microservice are written in Java, through Spark Framework.
I made some tests on the backends, and concluded the problem is not the report generation nor the data transfer:
Asking the microservice to save the generated Excel in a file within the server and then opening such file (hereby file A) in Excel shows that file A is not corrupted.
Asking the main backend server to save the Excel file that it receives from the microservice in a file within itself and then opening such file in Excel (hereby file B) shows that file B is not corrupted.
Downloading both file A and file B through FileZilla from their respective servers yields completely uncorrupted files.
As such, I believe it is safe to assume the Excel becomes corrupted somewhere between the time the file is received on the frontend and the time the user downloads such file. Additionally, the Catalina logs do not evidence any error that might potentially be happening.
I have read several posts that deal with the issue, including a bug report (https://github.com/angular/angular/issues/14083) that included a workaround via XMLHTTPRequest. However, none of the workarounds detailed were successful in solving my issue.
Attached is the code I am using to both obtain the Excel file from the backend and serve it to the user. I am including both an XMLHTTPRequest and an Angular http call (within comments) since those are the two main ways I have been trying to make this work. Additionally, please do take into account the code has been altered to remove information I do not wish to make public.
download(body) {
let reply = Observable.create(observer => {
let xhr = new XMLHttpRequest();
xhr.open('POST', 'URL', true);
xhr.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
xhr.setRequestHeader('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
xhr.setRequestHeader('Authorization', 'REDACTED');
xhr.responseType = 'blob';
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
var contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
var blob = new Blob([xhr.response], { type: contentType });
observer.next(blob);
observer.complete();
}
else {
observer.error(xhr.response);
}
}
}
xhr.send(JSON.stringify(body));
});
return reply;
/*let headers = new Headers();
headers.set("Authorization", 'REDACTED');
headers.set("Accept", 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
let requestOptions :RequestOptions = new RequestOptions({headers: headers, responseType: ResponseContentType.Blob});
return this.http.post('URL', body, requestOptions);*/
}
Hereby is the code to prompt the user to download the Excel. It is currently made to work with the XMLHTTPRequest. Please do note that I have also attempted to download without resorting to FileSaver, with no luck.
downloadExcel(data) {
let body = {
/*REDACTED*/
}
this.service.download(body)
.subscribe(data => {
FileSaver.saveAs(data, "Excel.xlsx");
});
}
Hereby are the versions of the tools I am using:
NPM: 5.6.0
NodeJs: 8.11.3
Angular JS: ^6.1.0
Browsers used: Chrome, Firefox, Edge.
Any help on this issue would be appreciated. Any additional information you may need I will be happy to provide.
I think what you want is CSV format which open in Excel, update your sevice as follow:
You should tell Angular you are expecting a response of type blob (Binary Large Object) that is your Excel/Csv file.
Also make sure the URL/API on your server is set to accept content-type='text/csv'.
Here's an example with Angular 2.
#Injectable()
export class YourService {
constructor(private http: Http) {}
download() { //get file from the server
this.http.get("http://localhost/..", {
responseType: ResponseContentType.Blob,
headers: new Headers({'Content-Type', 'text/csv'})
}).subscribe(
response => {
var blob = new Blob([response.blob()], {type: 'text/csv'});
FileSaver.saveAs(blob, 'yourFileName.csv');
},
error => {
console.error('something went wrong');
}
);
}
}
Have you tried uploading/downloading your xls file as base64?
var encodedXLSToUpload = 'data:application/xls;base64,' + btoa(file);
Check this for more details: Creating a Blob from a base64 string in JavaScript

Upload files in server using Meteor Files veliov group

I have this package nodemailer used in Meteor.
After getting the emails, I would like to save the attachments using Meteor Files.
The problem is I don't know how. Can anyone provide a simple example for uploading files in server code. I tried uploading in the client and successful. But when i tried Files.insert() in server, it have "not a function" error.
Here is my code in server,
var mailparser = new MailParser({
streamAttachments: true
});
Fiber(function() {
var timeStamp = Math.floor(Date.now());
mailparser.on("attachment", function(attachment, mail){
... code here to upload
mailparser.on("end", Meteor.bindEnvironment(function (mail_object) {
.... some code here
}));
mailparser.write(data);
mailparser.end();
client.dele(msgnumber);
}).run();
Because insert function is for client side only, I used write() function of Files API. Here is the link,
https://github.com/VeliovGroup/Meteor-Files/wiki/Write

How to send backend errors/success messages from Node.js to frontend in AngularJS controller?

I have an application built on the MEAN stack, with ExpressJS.
There is a need to send success or error messages from backend (NodeJS) to frontend (AngularJS) for example - to show when a file was successfully uploaded. Below - after app.post is successfully completed, I would like to show this result on frontend (in AngularJS).
app.post('/upload' , function (req, res) {
//busboy handles multi-part file upload
console.log('Post received to upload ...');
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
//only update if the filename was change or exists
if (filename!== undefined || filename !=='') {
//reset url
options.url = '';
console.log("Uploading the file " + filename);
console.log("before", options);
options.path = '/uploads/' + filename;
options.fileName = filename; //update file name
console.log("Updating options ...", options);
fstream = fs.createWriteStream(__dirname + '/uploads/' + filename); //path where the file will be uploaded
file.pipe(fstream);
fstream.on('close', function () {
console.log("Upload finished successfully ! Uploaded " + filename);
initOntology();//initialize the ontology from upload
initEdges();
});
}
});
});
Is there any way that I can send the result from NodeJS to AngularJS controller?
There is a similar question here, but unsolved.
You should use socket.io
When the frontend starts up, it connects to a 'socket connection'. This is a different protocol to HTTP. If it can't do so, it uses a degraded version of the connection which works over HTTP.
Either end of the connection can 'emit' a message, which gets sent to the other end. The backend can send messages to all clients or to specific ones. You would set up Angular to receive the message and create its own event which one or more controller could be listening for. See https://github.com/btford/angular-socket-io When the frontend wants to send a message back to the backend, it can use the socket, or just a regular HTTP POST, etc.
Using this with Angular and Node is quite standard, there should be lots of information out there on how to do it.
Just send a http response back using the res object :
res.status(200).send('OK')
When error, send, a error status
res.status(500).send(errorMsg)
For angular :
$http.post(...).then(function successCallback(response) {
// response with 200 status
}, function errorCallback(response) {
// response with status 500
});

XSockets do not connect from Firefox

I need to use web sockets for some interactions with the user. I have pretty much copypasted solution from here - http://xsockets.net/blog/angular-js-xsocketsnet and got an issue with Firefox (27.0.1).
When I try to make this call (TwoWayBinding is my XSockets controller, I'm using .NET MVC on host side):
var connect = function (url) {
var deferred = $q.defer();
socket = new XSockets.WebSocket(url);
socket.on(XSockets.Events.open, function (conn) {
$rootScope.$apply(function () {
deferred.resolve(conn);
});
});
return deferred.promise;
};
connect("ws://localhost:49200/TwoWayBinding").then(function (ctx) {
isConnected = true;
queued.forEach(function (msg, i) {
publish(msg.t, msg.d);
});
queued = [];
});
I always get an error from Firebug:
Firefox can't establish a connection to the server at ws://localhost:49200/TwoWayBinding.
this.webSocket = new window.WebSocket(url, subprotocol || "XSocketsNET");
The same code works well in Chrome, it gets connected and I'm getting messages sent from host. Mentioned methods are wrapped into angular service, but this all works, I do not think this should be a problem.
One thing I was able to figure out from Fiddler was this:
Chrome:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
3 200 HTTP Tunnel to localhost:49200 0 chrome:3976
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
6 101 HTTP localhost:49200 /TwoWayBinding?XSocketsClientStorageGuid=5cf5c99aafd141d1b247ed70107659e0 0 chrome:3976
Firefox:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1740 200 HTTP Tunnel to localhost:49200 0 firefox:1420
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1741 - HTTP localhost:49200 /TwoWayBinding -1 firefox:1420
Simply said - there is some additional parameter XSocketsClientStorageGuid in the response for Chrome which does not occur in the respose to FF. I'm not sure if that has any impact or if I'm completely wrong but will appreciate any advice if somebody experiences same issue.
Update:
It looks like the critical line is this one
socket = new XSockets.WebSocket(url);
as the socket is not created properly in Firefox. But I still not have the cause of this.
What version are you running on , did you make a new installation of XSockets.NET using the Nuget Package or did you use the git example mentioned in the quesion above?
I just did a test on FF 26.0 and 27.0.1 , and it did go well using this pice of example;
http://xsockets.github.io/XSockets.JavaScript.API/test/index.html
I will have a look at the old Angular example asap and makre sure it is fixed of there is a problem!
Kind regards
Magnus

Resources