Debugging multiple Google form submissions on single click? - javascript

I'm trying to do a kind of purchase request app built off of a Google Spreadsheet. For awhile, (like the whole time I've been working on this), my code was working. For each line in the order sheet, it would loop through the values, fill in the Google form inputs, submit the form, then start the process again.
Yesterday I noticed it was submitting each line twice submitting the first line once, second line twice, third line three times, and so on. Then it stopped submitting at all. Then it started again submitting multiple times, then stopped. Could you guys please take a look at my code and tell me what I'm doing wrong?
function formSubmit() {
//Create unique ID (number of milliseconds since 1/1/70)
var d = new Date();
var n = d.getTime();
var uniqueID = n.toString();
//Loop through the lines of the order, fill in the values, submit
$('.orderline').each(function(i, obj) {
//Stop the default redirect so we can submit multiple times
$('#ss-form').submit(function(e) {
e.preventDefault();
$.ajax({
url: "https://docs.google.com/a/vt.edu/forms/d/e/1FAIpQLSf77MuDLeqyPbuDCBcpVagi6-hdiUpgZtr0CbuJ3kO-vXPswg/formResponse",
data: $(this).serialize(),
type: "POST",
dataType: "jsonp",
success: function(data) {
console.log("Submission successful");
},
error: function(xhr, status, error) {
console.log("Submission failed: " + error);
},
});
});
$("#entry_1725077600").val(uniqueID);
var name = $("#personname").val();
var email = $("#personemail").val();
$("#entry_1352722479").val(name);
$("#entry_1024015951").val(email);
//etc.
$("#ss-form").submit();
});
The form is public if you guys want to take a look. Note I have two forms submitting at once on the same click; the one above is for the items in the order, the second one is for metadata about the order.
EDIT: formSubmit() is being called from a second function that uploads files to Google Drive (if there's a better way to do this please do let me know):
if(document.getElementById('fUpload').value!='') {
var user = gapi.auth2.getAuthInstance().currentUser.get();
var oauthToken = user.getAuthResponse().access_token;
var uploadObj = $("[id$=fUpload]");
var file = uploadObj.prop("files")[0];
var metadata = {
'title': file.name,
'description': " ",
'mimeType': file.type || 'application/octet-stream',
"parents": [{
"kind": "drive#file",
"id": "0B5zM5ktmwJ2fN0c3RWYxWC1rUzQ"
}]
};
var arrayBufferView = new Uint8Array(file);
var uploadData = new Blob(arrayBufferView, {type: file.type || 'application/octet-stream'});
try{
var uploader =new MediaUploader({
file: file,
token: oauthToken,
metadata: metadata,
params: {
convert:false,
ocr: false
}
});
uploader.upload();
} catch(exc){
showErrorMessage("Error: " + exc);
$("#fUpload").val(" ");
}
} else {
formSubmit();
}
});
And then for successful responses:
MediaUploader.prototype.onContentUploadSuccess_ = function (e) {
if (e.target.status == 200 || e.target.status == 201) {
var response = e.target.response; //Get the response body
var parsed = JSON.parse(response); //Parse the response body to JS object
var fileID = parsed.id; //Get the file ID from the response
var linkToFile = "https://drive.google.com/open?id=" + fileID;
$("#entry_1703377267").val(linkToFile); //Add the file ID as the value of the file ID input field
formSubmit(); //Run the rest of the form submit functions
this.onComplete(e.target.response);
} else if (e.target.status == 308) {
this.extractRange_(e.target);
this.retryHandler.reset();
this.sendFile_();
}
};
EDIT 2: I never see success or error messages in the console. Also, it looks like things aren't being submitted twice, they're being submitted in a pattern: first item once, second item twice, third item three times, etc.

Related

How to post file with ajax?

Trying to save a file to a db. I am using formData via javascript to append the file and adding this as a post object via ajax. for some reason nothing gets sent.
What am I doing wrong?
HTML
<input type="file" style="display: none;" class="btn btn-primary uploadFile">
script:
$(".saveImage")
.on("click",
function() {
var files = $(".uploadFile");
var data = new FormData();
data = $.OverWatch.worker.uploadFileHandler.addUploadFiles(files, data);
$.OverWatch.worker.postUserData("/Administration/AddUserImage", data, function () {
alert("done");
});
});
Functions above look like:
addUploadFiles: function (files, data) {
$.each(files, function (i, v) {
var file = $(this).data("files");
data.append("file", file);
});
return data;
}
postUserData:
postUserData: function(url, data, callback) {
$.LoadingOverlay("show");
$.ajax({
url: url,
type: 'POST',
data: data,
cache: false,
processData: false,
contentType: false,
dataType: "HTML",
success: function(data) {
if (callback) {
callback(data);
$.LoadingOverlay("hide");
}
},
error: function(event, jqxhr, settings, thrownError) {
//$.helpers.errorHandler($("#fileDialogErrors"), event.responseText);
var h;
$.LoadingOverlay("hide");
}
});
},
backend:
public ActionResult AddUserImage()
{
if (Request.Files.Count != 0)
{
//save
}
return null;
}
edit:
var files = $(".uploadFile");
returns:
Your var file = $(this).data("files"); line of code would be returning undefined (unless you have some other javascript adding a data value, but you cannot add files to data so it in any case it would not be returning a file).
Change your loop to
$.each(files, function (i, v) {
for (i = 0; i < v.files.length; i++) {
var file = v.files[i];
data.append("file", file);
}
});
However, you can simplify this by using var data = new FormData($('form').get(0)); which will serialize all you form controls including file inputs to FormData (refer how to append whole set of model to formdata and obtain it in MVC for more information).
I also recommend you change your method signature to
public ActionResult AddUserImage(IEnumerable<HttpPostedFileBase> files)
and let the DefaultModelBinder do its magic.
you can directly get file from controller when called using Request.Files
//(Request) HttpRequestBase object for the current HTTP request
if (Request.Files.Count > 0)//// Is image is uplaod by browse button
{
var inputStream = Request.Files[0].InputStream;
using (var binaryReader = new BinaryReader(inputStream))
{
var ImageBytes = binaryReader .ReadBytes(Request.Files[0].ContentLength); // same as you can get multiple file also
}
var fileExtension = Path.GetExtension(Request.Files[0].FileName);
}
thanks.
I haven't done it with jQuery but just learned how to do it myself yesterday using plain old javascript... the following worked for me. If you want to stick with jquery maybe you can translate the functions to what you need:
var formElement = document.querySelector("form");
var payload = new FormData(formElement);
function onStateChange(ev) {
// Check if the request is finished
if (ev.target.readyState == 4) {
editor.busy(false);
if (ev.target.status == '200') {
// Save was successful, notify the user with a flash
} else {
// Save failed, notify the user with a flash
}
}
};
xhr = new XMLHttpRequest();
xhr.addEventListener('readystatechange', onStateChange);
xhr.open('POST', '/posts');
xhr.send(payload);
Maybe see if using the above code works for you (it just targets a form that you have on the same page), and then you can troubleshoot whether it's your script that's the problem or a backend / communication problem.

When one ajax is SUCCESS load next

I have been looking into a jQuery Ajax queue system. I have a step by step generator. It generates a pdf and then once the pdf is generated an image is created. Once these 2 processes are complete I then send an email confirmation. It must also be flexible to add additional steps.
However, I have yet to find an example that works. They all use 'COMPLETE' rather than 'success' so if I return an error via jSON then it is ignored. It moves on to the next in the queue
Any ideas?
EDIT
It's quite complex whats happening.
My plugin (copied from another plugin)
$.AjaxQueue = function() {
this.reqs = [];
this.requesting = false;
};
$.AjaxQueue.prototype = {
add: function(req) {
this.reqs.push(req);
this.next();
},
next: function() {
if (this.reqs.length == 0)
return;
if (this.requesting == true)
return;
var req = this.reqs.splice(0, 1)[0];
var complete = req.complete;
var self = this;
if (req._run)
req._run(req);
req.complete = function() {
if (complete)
complete.apply(this, arguments);
self.requesting = false;
self.next();
}
this.requesting = true;
$.ajax(req);
}
};
I have also written a function to speed my code up
function createQueue(file, inputid, step, params) {
var queue = new $.AjaxQueue();
queue.add({
url: file,
type: 'POST',
dataType: "json",
data: params,
complete : function(data, status) {
$('li#step' + step + ' .loading').remove();
// DO SOMETHING. CANT CHECK FOR ERRORS
},
success : function(data, status) {
// DOES NOT WORK
},
error: function(xhr, desc, err) {
console.log(xhr);
console.log("Details: " + desc + "\nError:" + err);
},
_run: function(req) {
//special pre-processor to alter the request just before it is finally executed in the queue
//req.url = 'changed_url'
$('li#step' + step).append('<span class="loading"></span>');
}
});
}
Step 1. I am using mpdf to generate a pdf. Now this takes a few seconds to actually build depending on theme, images used etc. So i call this:
createQueue('post_pdf.php', id, 1, { 'filename': filename + '.pdf', 'id': id, 'crop': crop } );
Step 2 - Generate some images
createQueue('ajax_image.php', id, 2, { 'filename': filename + '.pdf' } );
Step 3 - (something else like send email summary)
createQueue('mail.php', id, 3, { 'from': 'newfilename', 'to': 'emavle#pb.com', 'subject': 'This is a subject', 'body': 'Body Copy' } );
If it fails at step 1 I can see it in console but its not returned
As #charlietfl suggested, have each step in PHP on server side. After the AJAX call is done, you can have the response from the server and continue based on that. Example:
// make AJAX request to file.php and send 'data'
var request = $.ajax({
url: "file.php",
type: "POST",
data: { data }
});
// when PHP is done, receive the output and act accordingly
request.done(function( msg ) {
if (msg == "A") {
// plan A
} else if (msg == "B") {
// plan B
}
});

"this is undefined error" in JS using Google Maps API

I can't seem to figure out this problem where the below code works when the "for loop" is disabled, and the attributes "locations" and "startAddress" are just simple strings. But if they are not, I am getting a "this is undefined" error when the ajax post request is submitted. Do you have any ideas why would this be? Any leads would be appreciated.
// create an event handler for the save route button
$("#saveRouteButton").click(function(){
var saveRouteName = $("#saveRouteNameField").val();
if (!saveRouteName) {
alert("Please supply a proper name to be submitted to the database");
} else {
var routeLength = directionsDisplay.getDirections().routes[0].legs.length;
var returnRoute = {
alias: null,
locations : [], // make this a string - it works!
startAddresses : [], // make this a string - it works!
};
// disable this loop - it works!
for (var i = 0; i < routeLength; i++){
returnRoute.locations[i] = directionsDisplay.getDirections().routes[0].legs[i].start_location
returnRoute.startAddresses[i] = directionsDisplay.getDirections().routes[0].legs[i].start_address
};
route_info = returnRoute;
route_info.alias = saveRouteName;
//test to see if the variables are set, they are!
alert(route_info.alias);
alert(route_info.locations);
alert($.isPlainObject(route_info))
$.ajax({
url: "save_route/",
type: "POST",
data : route_info,
success: function(data){
if (data != "None") {
$("#savedRoutesList").append('<li class="savedRoutesListItem">'
+ data + '</li>');
}
else {alert("You need to enter a route name");}
}
});
}
return false;
});
the error originates from the : google maps main js - line 13
Thanks!
Just check the route Length value,whether it is giving correct value or not?

Ajax IndexedDB Delete Current Sucesfull Upload

I posted something similar yesterday but it works but only deleted the last object in the data.
What I want to happen
This ajax upload will be handling a lot of data, so I'm using indexeddb. This will also be use on mobile phones. So I wanted it to upload one item at a time and if one item failed to have only deleted the previous items out of the data so they wouldn't need to upload everything again.
I have tried async = false, This works exactly how i want it but this freezers browser.
Current Code Tried to comment out any bits that could be confusing, currently this only deletes the last item once finished.
function uploadData(e) {
//Get Database
var transaction = db.transaction(["data"], "readonly");
var objectStore = transaction.objectStore("data");
var cursor = objectStore.openCursor();
//Starts Looping
cursor.onsuccess = function(e) {
var res = e.target.result;
if (res) {
if (navigator.onLine) {
$('.popup-heading').text('Uploading...');
var passData = {
client_id: res.value.client_id,
parent_id: res.value.parent_id,
storename: res.value.storename,
image: res.value.image,
key: res.key,
};
var jsonData = JSON.stringify(passData);
$.ajax({
url: "{{ path('destination_app_ajax') }}",
type: "post",
// Works but freezes browser
/*async, flase*/
data: {
"json": passData
},
success: function(JsonData) {
//Delete item once successfull
var t = db.transaction(["data"], "readwrite");
var request = t.objectStore("data").delete(passData.key);
t.oncomplete = function(event) {
console.log('item deleted');
};
},
error: function() {
$('.popup-heading').text('Upload Failed!');
}
});
} else {
$('.popup-heading').text('Please find stronger signal or wifi connection');
}
res.
continue ();
}
}
}
It sounds like you have a scope issue with passData. Inside of your loop, but before you defined var passData = ... try wrapping the codeblock with an anonymous function:
(function() {
/* Your code here */
}());
That should prevent passData from leaking into the global scope, which seems to be why your IDB code only works on the last loop. (passData is being redefined each time before your AJAX response is able to complete.)
Update: There is no loop, you're dealing with callbacks. What I see happening is that you're redefining your onsuccess handler on each Ajax request (and overwriting all values but the last), reusing the same transaction. Try moving this transaction code into the success callback for the AJAX request:
//Get Database
var transaction = db.transaction(["data"], "readonly");
var objectStore = transaction.objectStore("data");
var cursor = objectStore.openCursor();
That will create a closure and commit your delete transaction on each response. That means one transaction per AJAX request, and one onsuccess callback per AJAX request (with no redefining).
The only solution I found worked with this was to send the Key via ajax to php then delete from that.
HTML
var passData = {
.......
key: res.key,
};
.....
$.ajax({
url: "yourscript.php",
type: "post",
data: {
"json": passData
},
success: function(JsonData) {
jsonKey = JSON.parse(JsonData);
//Delete item once successfull
var t = db.transaction(["data"], "readwrite");
var request = t.objectStore("data").delete(parseInt(jsonKey.key));
t.oncomplete = function(event) {
console.log('item deleted', jsonKey.key);
};
}
PHP
$data = $_POST['json'];
$returnKey = json_encode(
array(
'key' => $data['key']
)
);

How to convert simple form submit to ajax call;

I have a form with input field which can be accessed like
var algorithm = document.forms["algoForm"]["algorithm"].value;
var input = document.forms["algoForm"]["input"].value;
and earlier call was
document.forms["algoForm"].submit();
and form was
<form name="algoForm" method="post" action="run.do">
It all run fine
Now I wanted convert it to the ajax call so that I can use the returned data from java code on the same page. So I used soemthing like
var algorithm = document.forms["algoForm"]["algorithm"].value;
var input = document.forms["algoForm"]["input"].value;
var data = 'algorithm = ' + algorithm + '&input = ' + input;
$.ajax(
{
url: "run.do",
type: "POST",
data: data,
success: onSuccess(tableData)
{ //line 75
alert(tableData);
}
}
);
However the above code doesn't run. Please help me make it run
Let's use jQuery's serialize to get the data out of the form and then use the jQuery's ajax function to send the data to the server:
var data = $("form[name=algoForm]").serialize();
$.ajax({
url: "run.do",
type: "POST",
data: data,
success: function(tableData){
alert(tableData);
}
});
data expects a literal object, so you need:
var data = {
'algorithm': algorithm,
'input': input
};
Instead of retrieving all the parameter value and then sending them separately (which can be done server side as well, using below code), Use this:
var $form = $("#divId").closest('form');
data = $form.serializeArray();
jqxhr = $.post("SERVLET_URL', data )
.success(function() {
if(jqxhr.responseText != ""){
//on response
}
});
}
divId is id of the div containing this form.
This code will send all the form parameters to your servlet. Now you can use request.getParameter in your servlet to get all the individual fields value on your servlet.
You can easily convert above jquery post to jquery ajax.
Hope this helps :)
// patching FORM - the style of data handling on server can remain untouched
$("#my-form").on("submit", function(evt) {
var data = {};
var $form = $(evt.target);
var arr = $form.serializeArray(); // an array of all form items
for (var i=0; i<arr.length; i++) { // transforming the array to object
data[arr[i].name] = arr[i].value;
}
data.return_type = "json"; // optional identifier - you can handle it on server and respond with JSON instead of HTML output
$.ajax({
url: $form.attr('action') || document.URL, // server script from form action attribute or document URL (if action is empty or not specified)
type: $form.attr('method') || 'get', // method by form method or GET if not specified
dataType: 'json', // we expect JSON in response
data: data // object with all form items
}).done(function(respond) {
console.log("data handled on server - response:", respond);
// your code (after saving)
}).fail(function(){
alert("Server connection failed!");
});
return false; // suppress default submit action
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
I don't know how but this one runs well,
var algorithm = document.forms["algoForm"]["algorithm"].value;
var input = document.forms["algoForm"]["input"].value;
$.post('run.do', {
algorithm : algorithm,
input : input
}, function(data) {
alert(data);
}
);

Categories