All Dev Tips code are open source and may be used and modified freely.>
AJAX requests are asynchronous by default, but they can easily be made synchronous with the "async" parameter set to false:
$.ajax({ url: methodUrl, async: false, type: "POST", data: data, success: fnSuccess, error: fnError });
The side effect of setting async to false is that browser code execution is blocked until the ajax call is completed. It will seem to the user that browser has locked up if on a slow network connection or the server is slow to respond.
Another problem with async=true when the server is responsing slowly is multiple requests if the user clicks multiple times on the button making the ajax request.
The jquery/javascript solution provided addresses all these issues.
How it works
In summary, user input to the webpage will immediately be inhibited when a user clicks on a button to make the ajax call. After 3/4 of a second a
spinner/loading gif with timer will display. The loading gif goes away and the webpage recognizes user input when the server returns a value to the webpage.
Calling AjaxCallbackTimer() starts the process. The necessary html is added to the page body if 'ajaxLock' is not found.
'ajaxLock' div is shown next. This is a div that covers the entire screen and takes focus (z-index),
preventing the user from interacting with any other controls until the ajax call has completed. It then calls setInterval() to call
AjaxCallBackCheck() every 100 milliseconds.
AjaxCallBackCheck() is called evey 100 milliseconds until the all ajax calls have completed.
AjaxCallBackCheck() shows the div 'ajaxBusy' if the server has not responded after 3/4 of a second.
This disables the webpage and displays the spinner/loading gif. A seconds counter is displayed after 1 second.
A timeout error message is displayed after 30 seconds (default value).
All ajax calls have completed when '$.active == 0'.
Timer calls to AjaxCallBackCheck() are canceled and #ajaxBusy and #ajaxLock are set to display:none using jquery .hide().
The webpage is then back to normal.
Testing
Add this code to your server side method (serverMethodName) called by the web client:
System.Threading.Thread.Sleep(5000);This will allow the spinner/loading gif to display.
These functions are part of the zpm class contained in zpm.js, part of ZPM.Net. They can be called using zpm.AjaxCallbackTimer(). The code below has been stripped of zpm referneces, and can be imbedded as is in a web page.
// ----------$.ajax busy timer ------------ let AjaxCallbackTimer = null; let AjaxMethodUrl = null; let AjaxWaitMilliSeconds = 30; function AjaxCallbackTimer(methodUrl, waitSeconds) { if (AjaxCallbackTimer == null) { AjaxWaitMilliSeconds = ((waitSeconds === undefined) ? 30 : waitSeconds) * 1000; // default timeout is 30 seconds AjaxMethodUrl = methodUrl; var $ajaxLock = $('#ajaxLock'); if ($ajaxLock.length == 0) { $('body').append( // add if not found '<div id="ajaxLock" style="display:normal; position:absolute; left:0; top:0; width:100%; height:100%; z-index:9999"></div>' + '<div id="ajaxBusy"' + ' style="display:none; position:absolute; opacity:.7; background:#aaa; left:0; top:0; width:100%; height:100%; z-index: 9999">' + ' <img src="/Content/images/loading.gif"' + ' style="position:absolute; top:50%; left:50%; width:100px; height:100px; margin-top:-50px; margin-left:-50px;">' + ' <div id="ajaxBusyCounter"' + ' style="position:absolute; top:50%; left:50%; width:50px; height:50px; margin-top:-12px; margin-left:-25px;text-align:center;' + ' font-weight: bold; font-size:1.8em; color:white;">0</div>' + '</div>'); } else $ajaxLock.show(); // lock user input AjaxCallbackTimer = setInterval(AjaxCallbackCheck, 100, new Date()); } } function AjaxCallbackCheck(startTime) { if ($.active == 0) { // no ajax calls active clearInterval(AjaxCallbackTimer); AjaxCallbackTimer = null; $('#ajaxBusy, #ajaxLock').hide(); } else if (((new Date()) - startTime) > 750 && AjaxCallbackTimer != null) { if ($('#ajaxBusy').is(':visible')) { var seconds = Math.floor(((new Date()) - startTime) / 1000); if (seconds > AjaxWaitMilliSeconds) { clearInterval(AjaxCallbackTimer); AjaxCallbackTimer = null; $('#ajaxBusy, #ajaxLock').hide(); alert("Server call " + AjaxMethodUrl + " timeout."); } else if (seconds > 0) $('#ajaxBusyCounter').text(seconds); } else { $('#ajaxBusyCounter').text(""); $('#ajaxBusy').show(); } } }
To make a synchronous ajax call:
// sample syncronized ajax call AjaxCallbackTimer("serverMethodName"); $.ajax({ url: serverMethodName, type: "POST", data: data, success: fnSuccess, error: fnError });
Download Loading gif here (click right mouse button and 'Save Picture As'):
Feel free to Contact Us if you find problems or have suggestions.