Tips for delaying form submission until the xhmhttprequest finishes

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.

Answer №1

The solution that proved effective was:

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

    uploadfile();

    document.getElementById('accountForm').submit();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adjusting the transparency level of the map outside a circular zone in the Google Maps JavaScript API v

Currently, I am adding a circle to my map: var optionsCircle = { center: latlang, map: map, radius: 1000, fillOpacity: 0.1, strokeWeight: 0 }; this.circle = new google.maps.Circle(optionsCircle); Instea ...

Using javascript to extract values from nested JSON structures without prior key knowledge

My JSON data is structured as follows: {"sensors": {"-KqYN_VeXCh8CZQFRusI": {"bathroom_temp": 16, "date": "02/08/2017", "fridge_level": 8, "kitchen_temp": 18, "living_temp": 17, ...

Leveraging Firebase and Cloud Functions to dynamically update values based on date conditions

In my database, I have a collection of consultations with the value 'date' in TimeStamp format (e.g. October 31, 2020 at 1:00:00 AM UTC+1) and another value called "status" which is either true or false. Each TimeStamp always has the same time - ...

Beginner Query: What is the method for retrieving this data in JavaScript?

I'm struggling with accessing a specific value in an Object in JavaScript for the first time. The JSON I'm working with is structured like this: { "payload":{ "params":{ "switch:0":{ &q ...

Tips on elevating a dragged div above all other elements when utilizing two scrollbars

Currently, I have two horizontal scrollers where I need to drag a div from the upper scroller to the lower scroller. While this functionality is working properly, there is an issue with the dragged div getting lost under the borders of the scroller during ...

Loading images in advance using jCarousel

I need help with preloading images on a jCarousel that loads a JSON feed and generates necessary HTML. Can anyone suggest a way to accomplish this task efficiently? $(".banner ul").jcarousel({ itemLoadCallback:loadTopBanner, auto: 6, wrap: ...

Emulating a button press on the login screen

I have been attempting to utilize jQuery to simulate a button click on a login page. Interestingly, the conventional JavaScript method functions as expected: document.getElementById('loginButton').click(); However, the same action using jQuery ...

If Bootstrap CSS is linked, custom CSS style rules will only take effect when added within a style tag

I’m currently facing an issue where my custom CSS rules are not being applied after linking Bootstrap in my project. I am using Bootstrap CSS for a custom layout and need to incorporate my own styling as well. When I link bootstrap.min.css followed by m ...

Stop users from being able to copy text on their smartphones' internet browsers

I am currently working on creating a competitive typing speed challenge using JavaScript. Participants are required to type all the words they see from a div into a textarea. In order to prevent cheating, such as copying the words directly from the div, o ...

Issue with AJAX Complete event not functioning

Currently, I am facing an issue with firing the .ajaxComplete function on a demo site. I have referred to this function from this link. Below is my code : <SCRIPT type="text/javascript"> <!-- /* Credits: Bit Repository Source: http://www.bit ...

Tips for assigning a JSON object as the resolve value and enabling autosuggestion when utilizing the promise function

Is there a way to make my promise function auto-suggest the resolved value if it's a JSON object, similar to how the axios NPM module does? Here is an example of how axios accomplishes this: axios.get("url.com") .then((res) => { Here, axios will ...

What causes the variance in style between the two div elements?

As I delve into the world of styled-components, I decided to create this component: import React from 'react' import styled from 'styled-components' const Row = styled.div` ` const Column = styled.div` flex: 0 0 50%; max-widt ...

What is the best way to transfer a row value from one table to another and then reinsert it back into the original table

I attempted to transfer a row value from one table to another and then back to the original table, but unfortunately, I was unable to find a solution. $('#one tbody tr td input.checkbox').click(function() { if ($(this).attr('checked&apo ...

What is the functionality of array equals useState declarations in JavaScript?

Within ReactJS functional components, the following line enables the creation of: A variable to keep track of the current count A method to update the state when invoked Here's an example in JavaScript: let [count, setCount] = useState([]); Can you ...

jQuery Mishap - Creating an Unspecified Issue

At the moment, my website displays a list of registered users in one column and their email addresses with checkboxes next to them in another column. Users can check the boxes and then click a submit button to generate a list of the selected emails separat ...

Tips for submitting a form with multiple fields that share the same name attribute using ajax:

I have created an HTML form <html> <head></head> <form> <input type="text" name="question[]" /> <input type="text" name="question[]" /> <input type="file" name="image" /> <input type="submit ...

What methods does YepNope.js offer for assigning dynamic names to scripts?

Currently, I am utilizing YepNope.js to handle the loading of my css and javascript files. My query is regarding whether there is a method to assign variable names to these scripts during the initial process. For example: yepnope({ test : Modernizr.cs ...

Trigger Object RuntimeError

Initially, I attempted to pass the object :id to the URL and it was successful. However, when I tried to pass the object to the list, I encountered a ReferenceError. index.ejs: <tr> <th class="text-center">AWB NO</th> <th c ...

eliminate several digits past the decimal place

I thought this would be a simple task, but I'm completely stuck with the code I currently have! https://i.sstatic.net/Y36Cg.png render: (num) => { return <span><b>{num.toFixed(2)}</b>%</span>; // rounding to two de ...

Using Vue's V-IF directive to compare dates

On my website, I have an object that contains a field named available_at with the date in the format of 2019-08-08 I have a working HTML table utilizing Vue bindings but I am unsure how to compare the timestamp above using the built-in Date.now() method ...