I am trying to convert some code from javascript to jquery.
Javascript Code: (I have got this code here)
window.onload = function () {
document.getElementById('uploader').onsubmit = function () {
var formdata = new FormData(); //FormData object
var fileInput = document.getElementById('fileInput');
//Iterating through each files selected in fileInput
for (i = 0; i < fileInput.files.length; i++) {
//Appending each file to FormData object
formdata.append(fileInput.files[i].name, fileInput.files[i]);
}
//Creating an XMLHttpRequest and sending
var xhr = new XMLHttpRequest();
xhr.open('POST', '/Home/Upload');
xhr.send(formdata);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
}
return false;
}
}
JQuery Code: (According to my application)
$('#AutoUploadFiles').click(function () {
var formdata = new FormData();
var fileInput = $("#AutomaticUploader");
for (var i = 0; i < fileInput.get(0).files.length; i++) {
formdata.append(fileInput.get(0).files[i].name, fileInput.get(0).files[i]);
}
$.ajax({
url: '/members/AutoUploadFile',
type: 'post',
data: formdata,
success: function () {
},
error: function () {
}
});
});
When I try to execute the above JQuery code I get 'Illegal Invocation' error in jquery.min.js file.
I am new to Web Programming, so I might have done some mistakes while converting to JQuery.
If anybody catches some mistake, please guide me.
the problem is the formdata is an object and can't be serialize as an ordinary string
var formdata = new FormData();
and in your code
type: 'post',
data: formdata, //<-- this is the problem
success: function () {
formdata must be serialize well as valid json data or else it can't be send by $.ajax() that's why your jquery version will not work. Please try other jquery uploader scripts because there are lot of them in google
The accepted answer doesn't work if you are sending files over the XHR as file objects can not be JSON encoded.
The only "workaround" is to disable jQuery's XHR data processing.
To disable it globally use
$.ajaxSetup({processData:false});
or do
$.ajax({
... Ajax Stuff Here,
processData: false
});
on each request.
Related
I have a simple form that shows/hides different field sets based on the selection of a select menu. This is using the scenario described in the Symfony docs here.
I am in the process of stripping jQuery from this site in favor of vanilla javascript, so I'm attempting to convert the AJAX script that sends the form data after the select changes to either XMLHttpRequest of Fetch API. However when doing so the Form's PreSubmit or PostSubmit events don't fire as they do when using the Ajax request.
At first I thought maybe the request headers were different and in some cases they were, so I made sure on the Fetch API version to exactly match mirror the Ajax request headers, and still the events do not fire. Only the PreSetData event fires.
This is the original AJAX
let $ptoType = $("#pto_type");
$ptoType.off('change').on('change', function () {
let $form = $(this).closest('form');
let data = {};
data[$ptoType.attr('name')] = $ptoType.val();
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
$('#formStep2').replaceWith(
$(html).find('#formStep2')
);
}
});
});
This is the attempt at the XMLHttpRequest
let ptoType = document.getElementById("pto_type");
ptoType.addEventListener('change', function () {
let xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === XMLHttpRequest.DONE) {
if (xmlHttp.status === 200) {
document.getElementById("formStep2").innerHTML = xmlHttp.response.getElementById('formStep2').innerHTML;
} else if (xmlHttp.status === 400) {
alert('There was an error 400');
} else {
alert('something else other than 200 was returned');
}
}
};
xmlHttp.open(form.getAttribute('method'), form.getAttribute('action'), true);
xmlHttp.responseType = "document";
xmlHttp.setRequestHeader("X-Requested-With", "XMLHttpRequest")
xmlHttp.send(data);
});
And this is the attempt with the Fetch API
let ptoType = document.getElementById("pto_type");
ptoType.addEventListener('change', function () {
let form = document.getElementById('form_pto_entry');
const formData = new FormData();
formData.append('type', ptoType.options[ptoType.selectedIndex].text);
fetch(form.getAttribute('action'), {
method: form.getAttribute('method'),
headers: new Headers({'content-type': 'application/x-www-form-urlencoded; charset=UTF-8','x-requested-with': 'XMLHttpRequest'}),
body: formData,
})
.then(response => response.text())
.then((body) => {
let bodyHtml = ConvertStringToHTML(body);
document.getElementById("formStep2").innerHTML = bodyHtml.querySelector('#formStep2').innerHTML;
})
.catch((error) => {
console.error('Error:', error);
});
});
let ConvertStringToHTML = function (str) {
let parser = new DOMParser();
let doc = parser.parseFromString(str, 'text/html');
return doc.body;
};
So watching the Network tab in the dev tools and doing a little debugging, the headers sent in the Fetch API version match the headers sent in the Ajax version, however the pre submit data event just never fires.
Based on the doc link you posted, I assumed that you are in symfony 6.1.
You can check the symfony UX component dedicated to this this may fix your problem in no time without any JS configuration. = Symfony UX Dependent form fields doc
I am new to laravel and i want to send a file to a controller using javascript. I've seen examples for FormData object but i do not want to use that because i want to get file object from Request Object in controller. Instead of FormData i am making a request_data string. i am successfully able to post string variables but when i put file inside that request_data string i am not unable to get the file inside controller. Below is my code.
javascript
var file = form.task_file.files[0];
var http = null;
var url = "http://".concat(window.location.hostname).concat("/pms/upload_task_file");
if (window.XMLHttpRequest) {
http = new XMLHttpRequest();
}
http.onreadystatechange = function () {
alert(http.response);
}
const request_data= `task_file=${file}`;
http.open('POST', url, true);
http.setRequestHeader('Content-type', 'multipart/form-data');
http.setRequestHeader("X-CSRF-Token", form.token.value);
http.send(request_data);
Controller
public function uploadFile(Request $req)
{
if ($req->hasFile('task_file')) {
echo 'Request Contains a file';
} else {
echo 'No File in Request Object';
}
}
In response i always get 'No File in Request Object'. What is the correct way of posting file to controller using java script using request_data. Please help.
Try using the FormData in ajax while you upload a file.
$('form').submit(function(event) {
event.preventDefault();
var formData = new FormData($(this)[0]);
$.ajax({
url: '{{ url('/agents') }}',
type: 'POST',
data: formData,
success: function(result)
{
location.reload();
},
error: function(data)
{
console.log(data);
}
});
});
var http = new XMLHttpRequest();
http.onreadystatechange = function(response){
if(http.status === 200 && http.readyState){
console.log(response)
}
}
http.setRequestHeader('Content-type', 'multipart/form-data');
http.setRequestHeader("X-CSRF-Token", form.token.value);
http.open('get','https://jsonplaceholder.typicode.com/todos/1')
http.send()
I am writing some React.js that will upload multiple photos at a time. I am currently trying to send a batch of photos to the server but I cannot seem to get the files to append to the formData.
I call this function on the onChange event of the input field:
batchUpload(e) {
e.preventDefault();
let files = e.target.files;
for (let i = 0; i < files.length; i++) {
let file = files[i],
reader = new FileReader();
reader.onload = (e) => {
let images = this.state.images.slice();
if (file.type.match('image')) {
images.push({file, previewURL: e.target.result});
this.formData.append('files', file); //THIS IS NOT APPENDING THE FILE CORRECTLY
this.setState({images});
}
};
reader.readAsDataURL(file);
}
this.props.setFormWasEdited(true);
}
Then once the save button is pressed I run this function:
saveClick(goBack, peopleIdArray) {
if (this.state.images.length > 0) {
let formData = this.formData;
formData.append('token', Tokens.findOne().token);
formData.append('action', 'insertPhotoBatch');
formData.append('tags', peopleIdArray);
formData.append('date', dateString());
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + JSON.stringify(pair[1]));
}
let xhr = new XMLHttpRequest();
xhr.open('POST', Meteor.settings.public.api, true);
xhr.onload = (e) => {
if (xhr.status === 200) {
// upload success
console.log('XHR success');
} else {
console.log('An error occurred!');
}
};
xhr.send(formData);
} else {
//signifies error
return true;
}
}
Everything seems to be fine until I append the files to the formData. What am I doing wrong?
If I'm not mistaken you problem is with this.formData.append('files', file);
Running this line in a for loop will get you 1 field with all the file appended to each other resulting in an invalid file.
Instead you must file the file "array" syntax used informs like so:
this.formData.append('files[]', file);
This way you get the files on server side as $_FILES['files']['name'][0], $_FILES['files']['name'][1], ... and like wise for other properties of the files array.
I hope you have solved your issues already. I am still stuck not understanding why it would seem that my formData is not bringing anything to my server, but I did find an issue with your code.
When you use
JSON.stringify(pair[1])
the result looks like an empty array. If you instead try
pair[1].name
you'd see that append actually did attach your file.
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
const formData = new FormData();
Object.keys(payload).forEach(item => {
formData.append([item], payload[item])
})
pass this formData to your API.
I asked about 5 month ago about rewriting my ajax call in pure Javascript. Here the original post: https://stackoverflow.com/questions/35415812/need-help-to-rewrite-my-jquery-ajax-call-to-plain-javascript
I never thought about to rewrite the script completely because it works but now i need to rewrite the whole script to plain js. I already startet.
Here is the jQUery/JS mix:
var cc = document.getElementsByClassName("cart-count");
var wc = document.getElementsByClassName("wishlist-count");
var url = wp_ajax.ajax_url;
var data = {
action: 'get_counts'
};
// JQUERY JS mixed VERSION
$.ajax({
type: 'POST',
url: url,
data: data,
success: function (data) {
var counts = JSON.parse(data);
console.log(data);
for(var i = 0; i < cc.length; i++){
cc[i].innerText=counts["cartCount"];
}
for(var i = 0; i < wc.length; i++){
wc[i].innerText=counts["wlCount"];
}
}
});
console says:
{"cartCount":"(1)","wlCount":"(3)"}
That's right!
But now i tried to rewrite the rest. Here the latest:
var cc = document.getElementsByClassName("cart-count");
var wc = document.getElementsByClassName("wishlist-count");
var url = wp_ajax.ajax_url;
var data = {
action: 'get_counts'
};
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
//document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
var counts = data
console.log(data);
for(var i = 0; i < cc.length; i++){
cc[i].innerText=counts["cartCount"];
}
for(var i = 0; i < wc.length; i++){
wc[i].innerText=counts["wlCount"];
}
console.log('done');
} else if (xmlhttp.status == 400) {
console.log('There was an error 400');
} else {
console.log('something else other than 200 was returned');
}
}
};
xmlhttp.open('POST', url, true);
xmlhttp.send(data);
It does't work. The console gives me not the value, just the var:
Object {action: "get_counts"}
My question/problem: How can i get the data action values without the jQuery ajax? Please no questions like "why not jQuery?".
Thanks for all help!!! Sorry for my english.
UPDATE:
I got it!
jQuery:
var data = {
action: 'get_counts'
};
JS:
url + '?action=get_counts'
add this
var data = JSON.parse(xmlhttp.responseText);//you have to parse result
before this
var counts = data
console.log(data);
You are not evaluating the AJAX response data, but the local variable data which is set above the AJAX call:
var data = {
action: 'get_counts'
};
You need to parse the AJAX response instead:
if (xmlhttp.status == 200) {
console.log( JSON.parse(xmlhttp.response) )
}
See: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response
Its happening because Ajax is async request which the browser handers in a different thread than the one which is processing your code. Normally jquery and other similar frameworks have callback methods defined for that but in pure JS implementation you can use
xmlhttp.responseText
to fetch the output once the request is done
Admittedly, there are similar questions lying around on Stack Overflow, but it seems none quite meet my requirements.
Here is what I'm looking to do:
Upload an entire form of data, one piece of which is a single file
Work with Codeigniter's file upload library
Up until here, all is well. The data gets in my database as I need it. But I'd also like to submit my form via an AJAX post:
Using the native HTML5 File API, not flash or an iframe solution
Preferably interfacing with the low-level .ajax() jQuery method
I think I could imagine how to do this by auto-uploading the file when the field's value changes using pure javascript, but I'd rather do it all in one fell swoop on for submit in jQuery. I'm thinking it's not possible to do via query strings as I need to pass the entire file object, but I'm a little lost on what to do at this point.
Can this be achieved?
It's not too hard. Firstly, take a look at FileReader Interface.
So, when the form is submitted, catch the submission process and
var file = document.getElementById('fileBox').files[0]; //Files[0] = 1st file
var reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = shipOff;
//reader.onloadstart = ...
//reader.onprogress = ... <-- Allows you to update a progress bar.
//reader.onabort = ...
//reader.onerror = ...
//reader.onloadend = ...
function shipOff(event) {
var result = event.target.result;
var fileName = document.getElementById('fileBox').files[0].name; //Should be 'picture.jpg'
$.post('/myscript.php', { data: result, name: fileName }, continueSubmission);
}
Then, on the server side (i.e. myscript.php):
$data = $_POST['data'];
$fileName = $_POST['name'];
$serverFile = time().$fileName;
$fp = fopen('/uploads/'.$serverFile,'w'); //Prepends timestamp to prevent overwriting
fwrite($fp, $data);
fclose($fp);
$returnData = array( "serverFile" => $serverFile );
echo json_encode($returnData);
Or something like it. I may be mistaken (and if I am, please, correct me), but this should store the file as something like 1287916771myPicture.jpg in /uploads/ on your server, and respond with a JSON variable (to a continueSubmission() function) containing the fileName on the server.
Check out fwrite() and jQuery.post().
On the above page it details how to use readAsBinaryString(), readAsDataUrl(), and readAsArrayBuffer() for your other needs (e.g. images, videos, etc).
With jQuery (and without FormData API) you can use something like this:
function readFile(file){
var loader = new FileReader();
var def = $.Deferred(), promise = def.promise();
//--- provide classic deferred interface
loader.onload = function (e) { def.resolve(e.target.result); };
loader.onprogress = loader.onloadstart = function (e) { def.notify(e); };
loader.onerror = loader.onabort = function (e) { def.reject(e); };
promise.abort = function () { return loader.abort.apply(loader, arguments); };
loader.readAsBinaryString(file);
return promise;
}
function upload(url, data){
var def = $.Deferred(), promise = def.promise();
var mul = buildMultipart(data);
var req = $.ajax({
url: url,
data: mul.data,
processData: false,
type: "post",
async: true,
contentType: "multipart/form-data; boundary="+mul.bound,
xhr: function() {
var xhr = jQuery.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position; /*event.position is deprecated*/
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
def.notify(percent);
}
}, false);
}
return xhr;
}
});
req.done(function(){ def.resolve.apply(def, arguments); })
.fail(function(){ def.reject.apply(def, arguments); });
promise.abort = function(){ return req.abort.apply(req, arguments); }
return promise;
}
var buildMultipart = function(data){
var key, crunks = [], bound = false;
while (!bound) {
bound = $.md5 ? $.md5(new Date().valueOf()) : (new Date().valueOf());
for (key in data) if (~data[key].indexOf(bound)) { bound = false; continue; }
}
for (var key = 0, l = data.length; key < l; key++){
if (typeof(data[key].value) !== "string") {
crunks.push("--"+bound+"\r\n"+
"Content-Disposition: form-data; name=\""+data[key].name+"\"; filename=\""+data[key].value[1]+"\"\r\n"+
"Content-Type: application/octet-stream\r\n"+
"Content-Transfer-Encoding: binary\r\n\r\n"+
data[key].value[0]);
}else{
crunks.push("--"+bound+"\r\n"+
"Content-Disposition: form-data; name=\""+data[key].name+"\"\r\n\r\n"+
data[key].value);
}
}
return {
bound: bound,
data: crunks.join("\r\n")+"\r\n--"+bound+"--"
};
};
//----------
//---------- On submit form:
var form = $("form");
var $file = form.find("#file");
readFile($file[0].files[0]).done(function(fileData){
var formData = form.find(":input:not('#file')").serializeArray();
formData.file = [fileData, $file[0].files[0].name];
upload(form.attr("action"), formData).done(function(){ alert("successfully uploaded!"); });
});
With FormData API you just have to add all fields of your form to FormData object and send it via $.ajax({ url: url, data: formData, processData: false, contentType: false, type:"POST"})