最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Waiting for an async call to finish before submitting a form - Stack Overflow

programmeradmin3浏览0评论

This one is a bit tricky.

So here's my jQuery code:

/**
 * Updating websites
 */
$('.website').on('blur', function () {
    var websiteId = this.id;
    console.log(websiteId);
    var website = this.value;
    console.log(website);
    fetch(`/api/edit/${websiteId}&${website}`).then(() => {

    });
})

Here's my HTML

<form method="post">
    <% for(let i = 0; i < websites.length; i++){ let website = websites[i]; %>
    <fieldset id="site<%= i %>">
        <p style="color: <% if(errorMsgs[i] === 'Wrong website address'){ %> red;<% } else { %> green;<% } %>
                padding-bottom: 0;
                padding-top: 10px;
                margin-bottom: 0;"
           class="">
            <%= errorMsgs[i] %>
        </p>
        <div class="">
            <input class="website"
                   name="website<%= i %>"
                   id="<%= i %>"
                   value="<%= website %>"
                   type="text"/>
            <a href="/websites/edit/<%= i %>"
               class="btn btn-info hide">
                Edit
            </a>
            <a href="/websites/delete/<%= i %>"
               data-id="<%= i %>"
               class="btn btn-danger confirmation removeBtn">
                Remove
            </a>
        </div>
    </fieldset>
    <% } %>
    <button type="submit"
            class="btn btn-primary col-sm-offset-2"
            value="Generate a report"
            name="generateReport"
            data-toggle="modal"
            data-target="#exampleModal">
        Generate a report
    </button>
    <!-- Save button created using Javascript. In case JS is disabled -->
</form>

Here's my API

// GET: api/edit/_id - save updates
router.get('/edit/:_id&:url', (req, res, next) => {
    Account.findById(req.user._id, (err, acc) => {
        if (err) {
            console.log(err);
        } else {
            acc.websites.set(req.params._id, req.params.url);
            acc.save((err, webs) => {
                if (err) {
                    console.log(err);
                } else {
                    console.log('all good');
                    // res.redirect('/reports');
                    res.json(webs);
                }
            });
        }
    });
});

How it works: The user inputs the value into the input fields, on blur, I make an AJAX call to the API, the value is saved in the db. And all this works.

There is one problem though. If the user hits the submit button, the fetch has no time to run. And it makes sense.

But I need the submission to wait until the value is updated. I was thinking about doing smth like, adding a preventDefault to the submit button, then after it's saved, removing the preventDefault.

But I have no idea how to do it, if it's a good idea or even if it makes any sense.

So to recap: I need the form submission to wait until the AJAX call is finalized.

This <% smth %> is just the EJS templating system. Shouldn't affect how it all works.

This one is a bit tricky.

So here's my jQuery code:

/**
 * Updating websites
 */
$('.website').on('blur', function () {
    var websiteId = this.id;
    console.log(websiteId);
    var website = this.value;
    console.log(website);
    fetch(`/api/edit/${websiteId}&${website}`).then(() => {

    });
})

Here's my HTML

<form method="post">
    <% for(let i = 0; i < websites.length; i++){ let website = websites[i]; %>
    <fieldset id="site<%= i %>">
        <p style="color: <% if(errorMsgs[i] === 'Wrong website address'){ %> red;<% } else { %> green;<% } %>
                padding-bottom: 0;
                padding-top: 10px;
                margin-bottom: 0;"
           class="">
            <%= errorMsgs[i] %>
        </p>
        <div class="">
            <input class="website"
                   name="website<%= i %>"
                   id="<%= i %>"
                   value="<%= website %>"
                   type="text"/>
            <a href="/websites/edit/<%= i %>"
               class="btn btn-info hide">
                Edit
            </a>
            <a href="/websites/delete/<%= i %>"
               data-id="<%= i %>"
               class="btn btn-danger confirmation removeBtn">
                Remove
            </a>
        </div>
    </fieldset>
    <% } %>
    <button type="submit"
            class="btn btn-primary col-sm-offset-2"
            value="Generate a report"
            name="generateReport"
            data-toggle="modal"
            data-target="#exampleModal">
        Generate a report
    </button>
    <!-- Save button created using Javascript. In case JS is disabled -->
</form>

Here's my API

// GET: api/edit/_id - save updates
router.get('/edit/:_id&:url', (req, res, next) => {
    Account.findById(req.user._id, (err, acc) => {
        if (err) {
            console.log(err);
        } else {
            acc.websites.set(req.params._id, req.params.url);
            acc.save((err, webs) => {
                if (err) {
                    console.log(err);
                } else {
                    console.log('all good');
                    // res.redirect('/reports');
                    res.json(webs);
                }
            });
        }
    });
});

How it works: The user inputs the value into the input fields, on blur, I make an AJAX call to the API, the value is saved in the db. And all this works.

There is one problem though. If the user hits the submit button, the fetch has no time to run. And it makes sense.

But I need the submission to wait until the value is updated. I was thinking about doing smth like, adding a preventDefault to the submit button, then after it's saved, removing the preventDefault.

But I have no idea how to do it, if it's a good idea or even if it makes any sense.

So to recap: I need the form submission to wait until the AJAX call is finalized.

This <% smth %> is just the EJS templating system. Shouldn't affect how it all works.

Share Improve this question asked May 8, 2018 at 14:26 Alex IronsideAlex Ironside 5,07914 gold badges76 silver badges134 bronze badges 1
  • 1 can't you set the disabled attribute on the button and remove it once you get the response in your .then? – p0rter Commented May 8, 2018 at 14:38
Add a ment  | 

3 Answers 3

Reset to default 4

It looks like fetch() returns a promise. Save those promises in a shared variable. In your submit button code, use Promise.all() to wait for all the promises to resolve. Something like:

const fetchPromises = [];
$('.website').on('blur', function () {
    var websiteId = this.id;
    console.log(websiteId);
    var website = this.value;
    console.log(website);
    var fetchPromise = fetch(`/api/edit/${websiteId}&${website}`).then(() => {

    });
    fetchPromises.push(fetchPromise);
});
$('form').on('submit', function (e) {
    e.preventDefault();
    Promise.all(fetchPromises).then(() => this.submit());
});

You may want to add some error handling. If any of your fetch() calls fail, that will prevent the form from being submitted. Ideally a failed AJAX call would result in some messaging to the user that, once dismissed, removes the promise from the fetchPromises array, and until it is dismissed, the submit button should be disabled (actually, and visibly).

How about making a fake submit button with a preventDefault and hiding your real submit button with display:none? Then you can call a click() function on the hidden button once you've got your AJAX success.

You could set your button to a disabled state, add a listener to it, then throwing an event during your .then() function.

$('.website').on('blur', function () {
    var elem = document.getElementById('submitButtonId');

    // create the event
    var isFinishedEvent = new Event('fetched');

    elem.addEventListener('fetched', function() {
        // logic to enable your button
    }

    var websiteId = this.id;
    console.log(websiteId);
    var website = this.value;
    console.log(website);
    fetch(`/api/edit/${websiteId}&${website}`).then(() => {
       // Fire the event
       elem.dispatchEvent(isFinishedEvent);
  });
})
发布评论

评论列表(0)

  1. 暂无评论