I am working on a Flask Web App that utilizes Boostrap and plain JavaScript. The challenge I am facing is related to making an XMLHttpRequest to upload a file to s3 when a form is submitted. However, the issue arises because the page reloads before the xhr returns, which cancels my request.
This problem seems to be quite common, and despite spending around 10 hours trying various solutions, only one method works reliably for me - adding a 3-second delay in my Flask App. By doing so, the xhr request gets enough time to process before the page reloads. Unfortunately, my current code encounters a roadblock after receiving the request and doesn't proceed further.
document.getElementById("accountForm").onsubmit = function (e) {
e.preventDefault();
uploadfile();
};
I have attempted every possible combination with this code snippet...
Tried changing 'accountForm' and 'onsubmit'
Experimented with 'onclick' as well...
Javascript
document.getElementById("accountForm").onsubmit = function (e) {
e.preventDefault();
uploadfile();
};
HTML
<form method="POST" action="" enctype="multipart/form-data" id="accountForm">
<input id="csrf_token" name="csrf_token" type="hidden" value="IjE1MjE0ZmM1OGMxNDI1NzMxZGY5N2E2MWFkMjExMDJmYmY3NjczMGEi.XFOE9Q.HVCiO1aeu0zWXG9nL0B1Z5mgnkE">
<fieldset class="form-group">
<legend class="border-bottom mb-4">Account Info</legend>
<div class="form-group">
<label class="form-control-label" for="username">Username</label>
<input class="form-control form-control-lg" id="username" name="username" required type="text" value="bill">
</div>
<div class="form-group">
<label class="form-control-label" for="email">Email</label>
<input class="form-control form-control-lg" id="email" name="email" required type="text" value="<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="44262d2828042329252d286a272b29">[email protected]</a>">
</div>
<div class="form-group">
<label for="picture">Update Profile Picture</label>
<input class="form-control-file" id="picture" name="picture" type="file">
</div>
</fieldset>
<div class="form-group">
<input class="btn btn-outline-info" id="submit" name="submit" type="submit" value="Update">
</div>
</form>
Javascript
function uploadfile() {
console.log("uploadfile main function called")
/* Check file exists and initiate temporary signature */
const files = document.getElementById('picture').files;
const file = files[0];
if (!file) {
return;
}
getSignedRequest(file);
/* Function to obtain the signature from the flask app */
console.log('Getting Signed request')
function getSignedRequest(file) {
const xhttp = new XMLHttpRequest();
//xhr.open('GET',`/sign-s3/?file-name=${file.name}&file-type=${file.type}`);
xhttp.onreadystatechange = function () {
console.log('ppReg: ' + this.readyState + " " + this.status)
if (this.readyState == 4 && this.status == 200) {
const response = JSON.parse(this.responseText);
console.log(this.readyState, this.status)
uploadFile(file, response.data, response.url);
}
};
xhttp.open('GET', `/s3Request/?file-name=${file.name}&file-type=${file.type}`);
xhttp.send();
// xhr.send();
}
/* Function to send the file to S3 */
function uploadFile(file, s3Data, url) {
console.log('uploading file after ppReq')
const xreq = new XMLHttpRequest();
xreq.onreadystatechange = function () {
console.log('s3Upload: ' + this.readyState + " " + this.status)
if (this.readyState == 4 && this.status == 204) {
//const response = JSON.parse(this.responseText);
//uploadFile(file,response.data,response.url);
console.log('File upload received by s3')
}
// else if (this.readyState == 4 && this.status != 204) {
// alert("File upload failed.")
else {
// switch to alert
console.log(this.readyState, this.status)
}
};
xreq.open('POST', s3Data.url, true); // set to false but need to change.
xreq.setRequestHeader('x-amz-acl', 'public-read');
const postData = new FormData();
for (key in s3Data.fields) {
postData.append(key, s3Data.fields[key]);
}
postData.append('file', file);
console.log(postData)
xreq.send(postData)
console.log('Data Sent!')
}
}
I anticipate that the form should not submit initially, then the uploadfile() function runs, and finally, the form submission occurs. However, the current code halts after the execution of uploadfile(). Any assistance on this matter would be greatly appreciated. I prefer sticking to vanilla JS wherever possible.
Edit: Although similar questions have been raised previously, I have tried all suggested solutions. Given my limited experience with JavaScript, understanding how a Promise relates to form submission remains a challenge for me. Nevertheless, I will continue exploring the topic. Thank you to those who are assisting in this endeavor.