Reputation: 5049
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.
Upvotes: 4
Views: 3832
Reputation: 91497
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).
Upvotes: 4
Reputation:
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);
});
})
Upvotes: 1
Reputation: 3434
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.
Upvotes: 1