I have the function "showElement" that has a setTimeout. How can I make that the calls to the function in the eventListener of the 'btnSend' execute one right after the other one?
I tried with .then() but didn't work.
document.getElementById('btnSend').addEventListener('click', e => {
e.preventDefault();
result = validateInputs(email, subject, message);
if(result) {
showElement(document.getElementById('formGroupSpinner'), 2000);
showElement(document.getElementById('formGroupSuccessImg'), 2000);
resetForm();
}
});
//expects an html element and a number representing miliseconds. Shows the html element for that amount of time.
function showElement(element, mSeconds) {
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
}, mSeconds);
}
Both functions execute at the same time.
There's many different approaches to this but I would suggest using a Promise like this:
document.getElementById('btnSend').addEventListener('click', e => { e.preventDefault(); var result = validateInputs(email, subject, message); if(result){ showElement(document.getElementById('formGroupSpinner'), 2000).then(()=>{ return showElement(document.getElementById('formGroupSuccessImg'), 2000); }).then(()=>{ resetForm(); }); } }); //expects an html element and a number representing miliseconds. Shows the html element for that amount of time. function showElement(element, mSeconds) { return new Promise((resolve, reject) => { element.classList.remove('d-none'); element.classList.add('d-block'); setTimeout( () => { element.classList.remove('d-block'); element.classList.add('d-none'); resolve(); }, mSeconds); }); }
Basically, the function after the .then()
only gets executed once you called the resolve();
.
Alternatively you could also use a callback or async / await .
you could use a callback to execute other instructions after the function has ended:
//First you add a param "callback" to the function
function showElement(element, mSeconds, callback) {
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
//Then you ask if the callback function is present and call it
if(callback && typeof callback === "function") callback();
}, mSeconds);
}
//Then use it in your event like this:
document.getElementById('btnSend').addEventListener('click', e => {
e.preventDefault();
result = validateInputs(email, subject, message);
if(result) {
showElement(document.getElementById('formGroupSpinner'), 2000, () => {
showElement(document.getElementById('formGroupSuccessImg'), 2000);
resetForm();
});
}
});
You can do this by using Promise
. You have to wrap your showElement()
function into a promise and call the promise resolver once setTimeout
fires. Then your calling code can pipe
your the promises together with then
:
showElement(document.getElementById('formGroupSpinner'), 2000).then(() => {
showElement(document.getElementById('formGroupSuccessImg'), 2000).then(() => {
resetForm();
});
});
However, this quickly leads to callback hell.
You can avoid this by using async/await
. You mark your function as async
, then you can use await
within it to wait for the promises to resolve before continuing to the next one:
await showElement(document.getElementById('formGroupSpinner'), 2000);
await showElement(document.getElementById('formGroupSuccessImg'), 2000);
resetForm();
Here is a working demo:
document.getElementById('btnSend').addEventListener('click', async e => { e.preventDefault(); await showElement(document.getElementById('formGroupSpinner'), 2000); await showElement(document.getElementById('formGroupSuccessImg'), 2000); }); function showElement(element, mSeconds) { return new Promise((resolve, reject) => { element.classList.remove('d-none'); element.classList.add('d-block'); setTimeout(() => { element.classList.remove('d-block'); element.classList.add('d-none'); resolve(); }, mSeconds); }); }
.d-none { display: none; } .d-block { display: block; }
<button id="btnSend">Send</button> <div id="formGroupSpinner" class="d-none">Spinner</div> <div id="formGroupSuccessImg" class="d-none">Success image</div>
The simplest way to do what you want is simply changing the second showElement to 4000 instead of 2000 .
That way one will have a timeout of 2 seconds and the other 4 seconds.
To make a promise chain, you first have to have a promise.
function showElement(element, mSeconds) {
return new Promise(function(resolve,reject){
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
resolve();
}, mSeconds);
}
}
Then you can use showElement().then(/*something here */)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.