Add external form elements to FormData - javascript

In HTML5 we can use the form attribute on form control elements to have them be part of a form other then the one they're childs of, as described in this answer.
These elements however seem not to be considered when passing the form element to the FormData constructor, as described on MDN.
Is there a way to have these 'external' controls be included in a way that I then can send the complete form data via a fetch Request?
I am aware, that I could loop through the external elements and append them to the FormData instance like so
let formData = new FormData(form);
for (const external of document.body.querySelectorAll('[form="' + form.name + '"]')) {
formData.append(external.name, external.value);
}
However I hoped for a more convenient way, especially taking in consideration the extra cases and checks I would have to make it work with radiobuttons etc.

Related

Submit binary data via Prototype Ajax call

I'm using Prototype to submit a POST request, and the postdata contains a number of fields, one of which is binary data from a file (in this case an Excel spreadsheet the user has selected for upload.)
I am using the HTML5 FileReader interface to get the contents of the file via FileReader.readAsBinaryString() which works well. If I use charCodeAt() to print various characters in the string then they come out with the expected values.
However once I put this string data in an object (along with the other form fields) and pass it as the parameters option to Prototype's Ajax.Request(), the data arrives corrupted. Certain character values like 0x82 are replaced with 0xC2 0x82, 0xAC is replaced with 0xC2 0xAC, and so on.
I tried using window.atob() to base64 encode the string, but this fails with InvalidCharacterError: String contains an invalid character, so clearly there is some kind of processing going on which I need to avoid.
Does anyone know how to pass binary data through Prototype's Ajax.Request() while also including additional form fields in the same request?
To do ajax file upload you should really use a FormData object
var data = new FormData();
//var data = new FormData(someForm); if all your fields is in an html form
// add fields to form
data.append('fieldname',fieldvalue);
data.append('filefieldname',fileobject);
//etc
new Ajax.Request(url, {
contentType: null,
method: 'post',
postBody: data,
onSuccess: successFunction
})
With this method the server will see the request like if it was sent by a form with attribute enctype="multipart/form-data"
Doing this requires magic and pixie dust. (well not really)
firstly you would need to put the form fields values as URL parameters instead of POST and then override the post body with the file contents. For example
new Ajax.Request('/url.php?rawupload=1&id='+$F('id')+'&label='+label,
{
'method':'post',
'postBody':fileobject,
'onSuccess':function() { alert('success'); }
});
fileobject is the HTML5 file object retrieved from the file upload input element
Yes its not the most elegant solution if you have lots of form fields. You can also use Hash#toQueryString if you do have lots of form fields to build your query string instead of doing them by hand
http://api.prototypejs.org/language/Hash/prototype/toQueryString/

mod_wsgi: Reading POSTed file content remains empty

I don't get it, I don't understand.
In a self-developed Python web framework I'm posting a file form element to the server using JavaScript.
var formData = new FormData();
formData.append('file', document.getElementById('file').files[0]);
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.send(formData);
The server, sporting mod_wsgi, receives the request like so:
if environ['REQUEST_METHOD'] == 'POST':
post_env = environ.copy()
post_env['QUERY_STRING'] = ''
form = cgi.FieldStorage(
fp=environ['wsgi.input'],
environ=post_env,
keep_blank_values=True)
Then, when I want to access the form field's content to save it to a file, the following will return an empty result:
form['file'].file.read()
(All code has been edited for simplicity)
What puzzles me is that the form field will show the correct file name and MIME type, only file.read() remains empty.
Also all other information from other input text fields comes through and is accessible.
I also checked that environ['REQUEST_METHOD'] is actually POST.
As to HTTP Headers for encoding (such as multipart/form-data), I thought that the XMLHttpRequest object will take care of that, once formData.append() receives a file input as the value.
Okay, here's the solution:
I can't explain it, but the file form fields get emptied on first read, which I found out by accident. Maybe a bug, who knows.
I assumed that they would stay intact (like any other variable) and can be read multiple times.
What I ignored was that I had in fact addressed them several times.
So the solution was to first store the file's content in a variable, and then use that multiple times.

FormData created from an existing form seems empty when I log it [duplicate]

This question already has answers here:
How to inspect FormData?
(22 answers)
Closed 6 years ago.
I'm trying to get a set of keys (input names or similar) and values (input values) from a web form:
<body>
<form>
<input type="text" name="banana" value="swag">
</form>
<script>
var form = document.querySelector('form');
var formData = new FormData(form);
</script>
</body>
According to the FormData documentation, formData should contain the keys and values from the form. But console.log(formData) shows formData is empty.
How can I quickly get the data from the form using FormData?
JSFiddle
Update: the XHR spec now includes several more functions to inspect FormData objects.
FireFox has supported the newer functions since v39.0, Chrome is slated to get support in v50. Not sure about other browsers.
var form = document.querySelector('form');
var formData = new FormData(form);
for (var [key, value] of formData.entries()) {
console.log(key, value);
}
//or
console.log(...formData)
I faced the same problem as well. I wasn't able to see on the console. You need to add the following to the ajax request, so the data will be sent
processData: false, contentType: false
But console.log(formData) shows formData is empty.
What do you mean by "empty"? When I test this in Chrome it shows ‣ FormData {append: function} ... which is to say it's a FormData object, which is what we expected. I made a fiddle and expanded to code to this:
var form = document.querySelector('form'),
formData = new FormData(form),
req = new XMLHttpRequest();
req.open("POST", "/echo/html/")
req.send(formData);
...and this is what I saw in the Chrome Developer Tools Network panel:
So the code is working as expected.
I think the disconnect here is that you're expecting FormData to work like a vanilla JavaScript object or array and let you directly look at and manipulate its contents. Unfortunately it doesn't work like that—FormData only has one method in its public API, which is append. Pretty much all you can do with it is create it, append values to it, and pass it to an XMLHttpRequest.
If you want to get the form values in a way you can inspect and manipulate, you'll have to do it the old-fashioned way: by iterating through the input elements and getting each value one-by-one—or by using a function written by someone else, e.g. jQuery's. Here's an SO thread with a few approaches to that: How can I get form data with JavaScript/jQuery?
As per MDN documentation on FormData
An object implementing FormData can directly be used in a for...of structure, instead of entries(): for (var p of myFormData) is equivalent to for (var p of myFormData.entries()).
Iterating over FormData.entries() didn't worked for me.
Here is what I do to check if formData is empty or not:
var isFormDataEmpty= true;
for (var p of formData) {
isFormDataEmpty= false;
break;
}
As iterating over formData gives you the uploaded file, you can use it for getting the file name, file type validation, etc.

Can't build a FormData object out of existing form

I'm trying to build a FormData object out of a form on my page. I'm getting the form element like this:
var form = document.forms['upload_form'];
And then I'm building the FormData object like this:
var fd = new FormData(form);
Since you cannot log values in a FormData object (as described here), I'm sending the formdata to '/' just so I can see its contents in my Network Inspector. The contents of the request payload are simply:
------WebKitFormBoundaryKAgAjii8IMLyJFcB--
and nothing else! If I manually append a value to the form like this:
fd.append("username", "Groucho");
it works:
------WebKitFormBoundaryZikgEBo7sTzvlndC
Content-Disposition: form-data; name="username"
Groucho
I've also tried selecting the form element in other ways, such as with jQuery:
var form = $(".upload_form");
var fd = new FormData(form[0]);
No matter how I select the form element, the form variable certainly does have the form in it (it's not null or empty), but constructing the FormData object with it as a parameter just does not seem to work. Can anyone help?
PS I'm using Chrome 31.0.1650.57. I've also tried this in Safari 7.0 with the same results.
Another thing: The inputs in this form are nested inside a number of divs. Could this be a problem?
This was happening because I didn't have name attributes set on my inputs. Apparently, new FormData() and $.serialize() will ignore any inputs without names.

How to override variable parameter loaded from another script

I have a script that loads the code dynamically. It is kind of a search engine. When I press a search button, the action gets triggered and a new page opens with many parameters.
I want to override one of the parameters generated with the script in the new URL. JS code is quite big and hard to read, but I have found the important part in the Firebug DOM editor.
This is the pattern of the URL generated when you perform the search:
http://www.example.com/...?ParameterOne=123&ParameterTwo=Two&ThisParameter=Sth&ParameterFour=Four...
What I want to edit is "ThisParameter" and change its value. This is the part edited in the DOM that does what I want:
Foobar = {
_options: [],
...
var options = {"ParameterOne":123,"ParameterTwo":"Two","ThisParameter":"ABC","ParameterFour":Four,...}
...
And this is the output of "ThisParameter" when you choose "Copy path" in Firebug's DOM tab:
_options[0].ThisParameter
I am wondering it this is possible at all. What makes me think that it is, is the fact that I can change this parameter in Firebug and it works perfectly. So, if Firebug can edit it, there should be a way to influence it with another script.
Looking forward to any suggestions, thank you in advance!
Since you cannot edit the dynamic script you have the following options:
You have to try to give the script the correct input and hope it uses your value.
Add a script to the results page which will read the url and arguments, change it and redirect, as we discussed here. (If you put everything in functions it should not conflict with the dynamic script if the functions are uniquely named.)
You could try adding something like this jQuery code to the page with the search button:
$('input[name=search_button_name]').click(function(e) {
e.preventDefault();
var form_search = $('#search_form_id');
$('<input>').attr({
type: 'hidden',
name: 'ThisParameter',
value: 'SomethingElse'
}).appendTo(form_search);
f.submit();
});
You can override any js function and method, or wrap you code around it. The easiest thing would be to look at the code you get and once it gets loaded, you re-declare a method with your own functionality.
I you are trying to replace a parameter in a specific jquery request, you can even wrap around the jquerys ajax method:
var jquery_ajax = $.ajax
$.ajax = function(options){
// parse only a specific occurence
if(options.url.indexOf("example.com") > -1) {
// change the url/params object - depending on where the parameter is
options.params.ThisParameter = "My Custom value"
}
// call the original jquery ajax function
jquery_ajax(options);
}
But it would be a lot cleaner to override the method that builds the ajax request rather than the ajax request itself.
I would investigate further on the scope of the variable options (var options), is it global? i.e. if you type 'options' in the Firebug console, does it display its properties?
If so, you could then access it via your own script and change is value, e.g.
options.ThisParameter = 'my-own-value';
You might hook your script to the click event of the search button.
I hope this helps, it could be more specific maybe if you have some sample code somewhere.

Categories

Resources