0

I have a Flask Web App using Boostrap and plain Javascipt. When a form is submitted I make an xmlhttprequest to upload a file to s3. The issue is that the page reloads before the xhr returns and cancels my request.

This question is asked a lot and I've tried every solution I've seen (10 hrs on this one issue!). The only solution that reliably works is to wait 3 secs in my Flask App. This allows the xhr request to process before page reload. My current code gets the request and then hangs. I can't get it to continue.

document.getElementById("accountForm").onsubmit = function (e) {
    e.preventDefault();
    uploadfile();
};

Tried every permutation of this I can find....
Tried changing to'accountForm' and 'onsubmit'
Tried 'onclick'...

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="bill@gmail.com">

            </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 exist and call for temporary signature */
    const files = document.getElementById('picture').files;
    const file = files[0];
    if (!file) {
        return;
    }
    getSignedRequest(file);
    /* Function to get 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 {
                // change 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 would expect the form to not be submitted, then uploadfile() to run and finally the form to be submitted. The current code stops after uploadfile() is ran. Any help would be really really appreaciated! I'm trying to stick with plain JS if possible.

Edit: I agree similar questions have been asked but I've tried all of their solutions. I'm new to Javascript so I don't know how the suggested post discussing a Promise relates to submitting a form. But I'll keep digesting it. Thanks to those who are looking.

warnerm06
  • 654
  • 1
  • 9
  • 20

1 Answers1

0

Here's what worked:

document.getElementById("accountForm").onsubmit = function (e) {
    e.preventDefault();

    uploadfile();

    document.getElementById('accountForm').submit();
warnerm06
  • 654
  • 1
  • 9
  • 20