Today I've been struggling to get some JavaScript code working.
The goal of this code is to have all of the files names returned by the ajax function calls populated within the fileNameObj
before the recordFormSubmission
function is called.
async function uploadSubmissionFiles(files)
{
//Get an array for the names of each key of the files object
var filesKeys = Object.keys(files);
var fileSubmissionErrors = [];
var formElementPK = "";
//Create an object that keeps track of the file names that are saved to the server
var fileNamesObj = {};
//For each question where we uploaded files, call an ajax function
//where we transfer the files from the client to the server
var promiseToUploadFiles = () => {
return new Promise((resolve,reject) =>
{
for(let i = 0; i < filesKeys.length; i++)
{
formElementPK = filesKeys[i].match("(?<=fpk).*");
console.log(formElementPK);
if(files[filesKeys[i]]["type"] == "canvas")
{
var canvasElement = files[filesKeys[i]]["response"];
var canvasImageBase64 = canvasElement.toDataURL().split(';base64,')[1];
//Use ajax to upload the file to the server
$.ajax(
{
url: "./includes/ajaxColdfusion/fillout/submittedFileUpload.cfc?method=uploadSubmittedCanvasImage",
type: "POST",
data: canvasImageBase64,
enctype: 'multipart/form-data',
contentType: false,
processData: false
}
)
.then( function(response)
{
var responseElements = response.getElementsByTagName("string");
var resultMessage = responseElements[0].innerHTML;
console.log("File upload result for " + canvasElement.id + ": " + resultMessage);
if(resultMessage == "success")
{
//On success, responseElements[1] contains the name of the file that was saved to the server. We record it!
fileNamesObj[formElementPK] = responseElements[1].innerHTML;
}
else
{
//On failure, responseElements[1] contains the error message for what happened during the upload
fileSubmissionErrors.push(responseElements[1].innerHTML);
fileNamesObj[formElementPK] = "error.png";
}
console.log(fileNamesObj);
}
);
}
else if(files[filesKeys[i]]["type"] == "fileUpload")
{
var fileUploadForm = files[filesKeys[i]]["response"];
var formData = new FormData(fileUploadForm);
var fileFieldName = document.getElementById("question" + formElementPK + "FileUpload").getAttribute("name");
formData.append("fileFieldName", fileFieldName);
//Use ajax to upload the file to the server
$.ajax(
{
url: "./includes/ajaxColdfusion/fillout/submittedFileUpload.cfc?method=uploadSubmittedFile",
type: "POST",
data: formData,
enctype: 'multipart/form-data',
contentType: false,
processData: false
}
)
.then( function(response)
{
var responseElements = response.getElementsByTagName("string");
var resultMessage = responseElements[0].innerHTML;
console.log("File upload result for " + fileUploadForm.id + ": " + resultMessage);
if(resultMessage == "success")
{
//On success, responseElements[1] contains the name of the file that was saved to the server. We record it!
fileNamesObj[formElementPK] = responseElements[1].innerHTML;
}
else
{
//On failure, responseElements[1] contains the error message for what happened during the upload
fileSubmissionErrors.push(responseElements[1].innerHTML);
fileNamesObj[formElementPK] = "error.png";
}
console.log(fileNamesObj);
}
);
}
}
var retObj = {
"fileSubmissionErrors" : fileSubmissionErrors,
"fileNames" : fileNamesObj
}
console.log("Resolved the promise!");
resolve(retObj);
});
}
return await promiseToUploadFiles();
}
async function recordFormSubmission(data, formPK, fileNames)
{
var JSONData = JSON.stringify(data);
var JSONFileNames = JSON.stringify(fileNames);
var submissionErrors = [];
console.log("Filenames at trigger of record form submission: ", fileNames);
console.log("Now waiting 2 seconds with await new Promise(r => setTimeout(r, 2000));");
await new Promise(r => setTimeout(r, 2000));
console.log("Fileanmes after 2 seconds of triggering record form submission", fileNames);
$.ajax(
{
url: "./includes/ajaxColdfusion/fillout/recordFormSubmission.cfc?method=recordFormSubmission",
type: "POST",
data: "JSONData=" + JSONData + "&formPK=" + formPK + "&JSONFileNames=" + JSONFileNames,
enctype: 'multipart/form-data',
cache : false
}
).
done(function(response)
{
//If successful...
console.log("Record form submission successful:" + response.getElementsByTagName("string")[0].innerHTML);
}
).
fail(function(response)
{
//If not successful...
console.log("Record form submission failed");
submissionErrors = [response.getElementsByTagName("string")[1]];
}
);
return submissionErrors;
}
uploadSubmissionFiles(filesToUpload.then( function(fromUploadSubmissionFiles)
{
var fileSubmissionErrors =
fromUploadSubmissionFiles["fileSubmissionErrors"]
var fileNames = fromUploadSubmissionFiles["fileNames"];
//Query the database to save our form data to the database
var formDataSubmissionErrors = recordFormSubmission(dataToRecord, formPK, fileNames);
}
Above are all the important parts of this code. As it stands right now though, recordFormSubmission() gets called and executes before the fileNamesObj variable is populated with file names that are returned from the ajax function. This must mean that the code is not waiting on the ajax to finish executing before continuing with execution, even though a promise has been implemented.
I suppose my question here is, what am I doing wrong if I want the JavaScript code to wait until all of the ajax functions are completed before calling recordFormSubmission()
?
I could probably think of a polling solution here, but I'd like to think that there's a way to solve this with promises or better practice.
This is the result of running the modified code to return an awaited promise. It also shows how the ajax functions return and the filenames are obtained in the window of time between waiting two seconds and when the critical point where the filenames must exist occurs.