How to upload a file with scalajs-react and AJAX - ajax

I want to send a file with Scalajs-react and Ajax. The sending part is easy with Ajax.send(requestBody: js.Any) method in the onSubmit method of my form (which I took care to stop the event propagation with preventDefault). To build the request body I use FormData(event.target).
def f(e: ReactFormEvent) = {
Ajax
.post("http://localhost:9000/rpc/v1/test/update-dataset")
.setRequestHeader("X-Requested-With", "XMLHttpRequest")
.send({
new FormData(
e.target
.asInstanceOf[dom.raw.HTMLFormElement]
)
})
.validateStatusIs(200)(Callback.throwException)
.asCallback
}
Form(onSubmit = e => f(e) >> e.preventDefaultCB)(
FormGroup("groupInput")(
FormFile(label = "Input")(),
UncontrolledFormControl(ref = ref, defaultValue = "abc")()
),
Button(`type` = "submit")("Submit")
)
Looks good, but for some reason the request body does not contain anything (ex: ------WebKitFormBoundaryAnYzDUdxWxA8hrJR--) as if FormData did not manage to retrieve the data from the form.
Here is a printout of the two children of e.target where we can see that both inputs have a non-empty value:
__reactFiber$ipxb5pt9wbi,[object Object],__reactProps$ipxb5pt9wbi,[object Object],_wrapperState,[object Object],__reactEvents$ipxb5pt9wbi,[object Set],value,C:\fakepath\artifacts.zip,_valueTracker,[object Object]
__reactFiber$ipxb5pt9wbi,[object Object],__reactProps$ipxb5pt9wbi,[object Object],_wrapperState,[object Object],__reactEvents$ipxb5pt9wbi,[object Set],value,abc,_valueTracker,[object Object]
Note: When I manually append items to the FormData, there are present in the body request.
What am I doing wrong?

Not sure why new FormData(formElement) isn't working, but building manually the FormData works. Ex:
send{
val fd = new FormData()
val elem = dom.document
.getElementById("form-inputf")
.asInstanceOf[HTMLInputElement]
fd.append("file", elem.files(0))
fd
}
If only one file needs to be send, one doesn't even need to use FormData at all. Simply relying on the File API is enough. Ex:
send{
val elem = dom.document
.getElementById("form-inputf")
.asInstanceOf[HTMLInputElement]
elem.files(0)
}

Related

Receiving null parameters from request in JSP file when are being sent

I've a JSP app. It uploads a file, but to do so the user has to authenticate using a name and a password. So my JSP file starts with:
//0.2.- We get the password
String password = (String) request.getParameter("pass"); // -> This returns NULL
//0.3.- We get the "uvus"
String uvus = (String) request.getParameter("uvus"); //-> This also returns NULL
//More code
So I'm trying to know why am I getting null from those variables.
I went to the form I was uploading, and look for the data that was being sent. Using Firefox Debug Tools, I saw:
So in fact, it was being sent.
As additional info, I'm building the request like this:
var pUvus = document.getElementById("uvus").value;
var pPassword = document.getElementById("pass").value;
var file = document.getElementById("userFile");
var formData = new FormData();
formData.append("upload", file.files[0]);
formData.append("uvus", pUvus);
formData.append("pass", pPassword);
xmlhttp.open("POST","uploadFile.jsp",true);
xmlhttp.send(formData);
At last, I would like to say that I can get vars from application object in the same JSP with no errors, and have received in another pair of JSP files vars at request object without more problems, so I think my fault should be in the way I'm building the request in Ajax, but I've no more clue about that...
Anyone can guide me?
Thanks for your help
Update: #rickz asked for how do I get the file and parse the request (what is done after my problem, trying to get the objects from the request scope):
List items;
items = servlet_up.parseRequest(request);
for(int i=0;i<items.size();i++)
{
FileItem item = (FileItem) items.get(i);
if (! item.isFormField())
{
request.getParameter() won't work for a multipart/form-data request.
If you are using org.apache.commons.fileupload then you should be using something like
if(item.isFormField()){
name = item.getFieldName();
...
}

Get Picture from Client - save on MongoDB, expressJS, nodeJS

I'm trying to Implement a simple Picture upload from the client to my mongoDB.
I've read many explanations but I can't find a way from start to finish.
My clientside -
function profilePic(input) {
if (input.files && input.files[0]) {
var file = input.files[0];
localStorage.setItem('picture', JSON.stringify(file));
}
}
Later on I take the this JSON from the LocalStorage and send it to my server side like this:
var request = false;
var result = null;
request = new XMLHttpRequest();
if (request) {
request.open("POST", "usersEditProf/");
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
.....//More code to send to Server
request.setRequestHeader('content-type', 'application/json');
request.send(JSON.stringify(localStorage.getItem('picture)));
}
}
On my serverside:
app.post('/usersEditProf/',users.editProfile);
/** Edits the Profile - sends the new one **/
exports.editProfile = function(req, res) {
var toEdit = req.body;
var newPic = toEdit.picture;
And thats where I get lost. is newPic actually holding the picture? I doubt it...
Do I need to change the path? What is the new path I need to give the picture?
How do I put it in my DB? Do I need GridFS?
When trying to simply put that in my collection, it looks like this (example with a image called bar.jpg:
picture: "{\"webkitRelativePath\":\"\",\"lastModifiedDate\":\"2012-10-08T23:34:50.000Z\",\"name\":\"bar.jpg\",\"type\":\"image/jpeg\",\"size\":88929}",
If you want to upload a blob through XMLHTTPRequest(), you need to use an HTML 5 FormData object:
https://developer.mozilla.org/en-US/docs/Web/API/FormData
It alows you to specify a filename to push, then you handle the incoming file as you would with a mime form post. Note the limitations on browser support when you use the FormData object. Your alternative is a form POST to a hidden frame, which works OK but is not nearly as clean looking in code as FormData.

can't seem to get progress events from node-formidable to send to the correct client over socket.io

So I'm building a multipart form uploader over ajax on node.js, and sending progress events back to the client over socket.io to show the status of their upload. Everything works just fine until I have multiple clients trying to upload at the same time. Originally what would happen is while one upload is going, when a second one starts up it begins receiving progress events from both of the forms being parsed. The original form does not get affected and it only receives progress updates for itself. I tried creating a new formidable form object and storing it in an array along with the socket's session id to try to fix this, but now the first form stops receiving events while the second form gets processed. Here is my server code:
var http = require('http'),
formidable = require('formidable'),
fs = require('fs'),
io = require('socket.io'),
mime = require('mime'),
forms = {};
var server = http.createServer(function (req, res) {
if (req.url.split("?")[0] == "/upload") {
console.log("hit upload");
if (req.method.toLowerCase() === 'post') {
socket_id = req.url.split("sid=")[1];
forms[socket_id] = new formidable.IncomingForm();
form = forms[socket_id];
form.addListener('progress', function (bytesReceived, bytesExpected) {
progress = (bytesReceived / bytesExpected * 100).toFixed(0);
socket.sockets.socket(socket_id).send(progress);
});
form.parse(req, function (err, fields, files) {
file_name = escape(files.upload.name);
fs.writeFile(file_name, files.upload, 'utf8', function (err) {
if (err) throw err;
console.log(file_name);
})
});
}
}
});
var socket = io.listen(server);
server.listen(8000);
If anyone could be any help on this I would greatly appreciate it. I've been banging my head against my desk for a few days trying to figure this one out, and would really just like to get this solved so that I can move on. Thank you so much in advance!
Can you try putting console.log(socket_id);
after form = forms[socket_id]; and
after progress = (bytesReceived / bytesExpected * 100).toFixed(0);, please?
I get the feeling that you might have to wrap that socket_id in a closure, like this:
form.addListener(
'progress',
(function(socket_id) {
return function (bytesReceived, bytesExpected) {
progress = (bytesReceived / bytesExpected * 100).toFixed(0);
socket.sockets.socket(socket_id).send(progress);
};
})(socket_id)
);
The problem is that you aren't declaring socket_id and form with var, so they're actually global.socket_id and global.form rather than local variables of your request handler. Consequently, separate requests step over each other since the callbacks are referring to the globals rather than being proper closures.
rdrey's solution works because it bypasses that problem (though only for socket_id; if you were to change the code in such a way that one of the callbacks referenced form you'd get in trouble). Normally you only need to use his technique if the variable in question is something that changes in the course of executing the outer function (e.g. if you're creating closures within a loop).

JSON output from web method

I have a web method returning JSON to a fullCalendar as event data but a "()" is added to it causing a parser error.
I am able to clip off the unwanted "()" and then attach the events with jQuery but obviously don't want to keep it this way.
The source of the data is a web method using Razor. Using the JSON helper to encode the data results in a well formed JSON string, i.e. no "()". Of course if I use encode I then would use Response.Write to send the data back to the AJAX function. The same ill formed JSON data is recieved if I use JSON.Write(data, Response.Output).
Catching the returned data in the success function shows the data with the attached "()".
Here is a portion of the web method that returns the data:
// convert the header names and data to strings
var rows = from e in cE
select new
{
id = e.EvId,
title = e.Title,
start = e.startT,
allDay = false,
end = e.endT,
backgroundColor = e.eventColor
};
string mJson = Json.Encode(rows);
//Json.Write(rows, Response.Output);
Response.Write(mJson.Trim());
here is the result of the encode:
"[{\"id\":9,\"title\":\"new event\",\"start\":\"2012-05-29 19:00:00\",\"allDay\":false,\"end\":\"2012-05-29 20:00:00\",\"backgroundColor\":\"Orange \"},{\"id\":9,\"title\":\"new event\",\"start\":\"2012-06-05 19:00:00\",\"allDay\":false,\"end\":\"2012-06-05 20:00:00\",\"backgroundColor\":\"Orange \"},{\"id\":9,\"title\":\"new event\",\"start\":\"2012-06-12 19:00:00\",\"allDay\":false,\"end\":\"2012-06-12 20:00:00\",\"backgroundColor\":\"Orange \"},{\"id\":10,\"title\":\"another\",\"start\":\"2012-06-22 19:00:00\",\"allDay\":false,\"end\":\"2012-06-22 19:45:00\",\"backgroundColor\":\"Orange \"},{\"id\":10,\"title\":\"another\",\"start\":\"2012-06-29 19:00:00\",\"allDay\":false,\"end\":\"2012-06-29 19:45:00\",\"backgroundColor\":\"Orange \"}]" string
Here is what the AJAX success function shows as the recieved data:
"[{"id":9,"title":"new event","start":"2012-05-29 19:00:00","allDay":false,"end":"2012-05-29 20:00:00","backgroundColor":"Orange "},{"id":9,"title":"new event","start":"2012-06-05 19:00:00","allDay":false,"end":"2012-06-05 20:00:00","backgroundColor":"Orange "},{"id":9,"title":"new event","start":"2012-06-12 19:00:00","allDay":false,"end":"2012-06-12 20:00:00","backgroundColor":"Orange "},{"id":10,"title":"another","start":"2012-06-22 19:00:00","allDay":false,"end":"2012-06-22 19:45:00","backgroundColor":"Orange "},{"id":10,"title":"another","start":"2012-06-29 19:00:00","allDay":false,"end":"2012-06-29 19:45:00","backgroundColor":"Orange "}]();???"

How to send large text in AJAX Request using prototype?

I have a situation where I have to send a large text in ajax request using method :POST. I have tried to do like this.
new Ajax.Request(url + "?" + params, {
method: 'post',postBody: {'Test':'Test'}, onSuccess: function (transport) {
switch (transport.responseJSON.Status) {
case "Success":
// alert(transport.responseJSON.Message);
var imgDiv = document.getElementById(control);
imgDiv.style.display = 'none';
break;
case "Failed":
alert(transport.responseJSON.Message);
break;
case "NotAuthorized":
alert(transport.responseJSON.Message);
break;
case "LoginRequired":
window.location = transport.responseJSON.RedirectAfterLogin;
break;
}
}
});
Test in post body will be replaced with large text from a text area. But when I try to access it on server like this
string test = context.Request["Test"];
I get null.
Any solution reference to an example?
Thanks
Write
postbody:'Test=Test'
instead of
postbody: {'Test':'Test'}
As your text is large, so use escape() function so that it is transmitted to server safely. Also be sure that your query string and post body params not clash with each other.
postBody is expected to be a name/value pair like this:
postbody:'Test=Test'
You would also need to add evalJSON = true if you want to use responseJSON assuming your returned content type is actually JSON

Resources