The following function mimics a pattern of behavior I would like in my system:
Press button
Change text to an Icon
Ask for user confirmation
Fire Ajax call to an endpoint, and handle the result
Return the text to the previous state.
As it is written, step 3 happens before steps 2 and 4; making step 2 borderline pointless. The Ajax call as I have it in my system loads pretty quickly, but the jQuery function barely blinks the text across. I have made a testable snippet here.
How do I ensure that step 2 correctly in order?
function callAjax() {
$('#loadingIcon').css('display', 'inline-block');
$('#buttonText').css('display', 'none');
if (confirm('Are you sure would you like to proceed?')) {
$.ajax({
url: "...",
timeout: 60000,
context: document.body,
success: function (data) {
location.reload();
},
error: function (data) {
$('#loadingIcon').css('display', 'none');
$('#buttonText').css('display', 'initial');
}
});
} else {
$('#loadingIcon').css('display', 'none');
$('#buttonText').css('display', 'initial');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onClick=callAjax()>
<span id="buttonText">Loading Text</span>
<span id="loadingIcon" style="display:none;">Icon</span>
</button>
CodePudding user response:
The UI doesn't update until the thread has finished doing what it's doing, and confirm
(and prompt
, and alert
) is a blocking operation.
Ideally you wouldn't use confirm
at all. Instead, create a UI within the page to prompt the user for data. It could be form elements on the page, a "modal dialog", etc.
But if you want to use confirm
, you'd need to allow the thread to finish first. It's a bit of a hack, but wrapping it in a near-immediate setTimeout
should do the trick:
$('#loadingIcon').css('display', 'inline-block');
$('#buttonText').css('display', 'none');
setTimeout(function () {
if (confirm('Are you sure would you like to proceed?')) {
$.ajax({
/* etc. */
});
} else {
$('#loadingIcon').css('display', 'none');
$('#buttonText').css('display', 'initial');
}
}, 1); // only delaying 1ms
This introduces a 1ms delay, which would certainly be imperceptible. But by virtue of using setTimeout
at all, the thread first finishes everything it's processing (including UI updates) and then executes what's scheduled in the timeout.