This is quite needed and required thing - have a good progress indicator that the same time blocks whole screen to prevent sending several simultaneous asynchronous requests to the server. So I decided to place a code that I currently use.
Actually this code is a synthesis of codes I already have seen in some blog posts in the Internet, but it is customized to my current needs.
The indicator blocks all controls on the page while update is in progress. Also it provides two handy methods we can use to invoke progress indicator before calling web service, and hide it after response. For simple postback with UpdatePanel controls it is shown automatically.
You may want to have a look at live sample, or download source code.
Let's see the code.
JS file:
function applicationLoadHandler() { /// <summary>Raised after all scripts have been loaded and the objects in the application have been created and initialized.</summary> }; function applicationUnloadHandler() { mainForm.CleanUp(); mainForm = null; Sys.Application.dispose(); }; function beginRequestHandler() { /// <summary>Raised after an asynchronous postback is finished and control has been returned to the browser.</summary> mainForm.StartUpdating(); }; function endRequestHandler() { /// <summary>Raised before processing of an asynchronous postback starts and the postback request is sent to the server.</summary> // Set status bar text if any was passed through the hidden field on the form mainForm.EndUpdating() }; var mainForm = { pnlPopup : "pnlPopup", innerPopup : "innerPopup", updating : false }; mainForm.StartUpdating = function() { mainForm.updating = true; mainForm.AttachPopup(); mainForm.onUpdating(); $get(mainForm.pnlPopup).focus(); }; mainForm.EndUpdating = function() { mainForm.updating = false; mainForm.DetachPopup(); mainForm.onUpdated(); }; mainForm.onUpdating = function(){ if(mainForm.updating) { var pnlPopup = $get(this.pnlPopup); pnlPopup.style.display = ''; var docBounds = mainForm.GetClientBounds(); var pnlPopupBounds = Sys.UI.DomElement.getBounds(pnlPopup); var x = docBounds.x + Math.round(docBounds.width / 2) - Math.round(pnlPopupBounds.width / 2); var y = docBounds.y + Math.round(docBounds.height / 2) - Math.round(pnlPopupBounds.height / 2); Sys.UI.DomElement.setLocation(pnlPopup, x, y); //if(Sys.Browser.agent == Sys.Browser.InternetExplorer) { if(!pnlPopup.iFrame) { var iFrame = document.createElement("IFRAME"); iFrame.scrolling= "no"; iFrame.src = "nothing.txt"; iFrame.frameBorder = 0; iFrame.style.display = "none"; iFrame.style.position = "absolute"; iFrame.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"; iFrame.style.zIndex = 1; pnlPopup.parentNode.insertBefore(iFrame, pnlPopup); pnlPopup.iFrame = iFrame; } pnlPopup.iFrame.style.width = docBounds.width + "px"; pnlPopup.iFrame.style.height = docBounds.height + "px"; pnlPopup.iFrame.style.left = docBounds.x + "px"; pnlPopup.iFrame.style.top = docBounds.y + "px"; pnlPopup.iFrame.style.display = "block"; //} } } mainForm.onUpdated = function() { // get the update progress div var pnlPopup = $get(this.pnlPopup); // make it invisible pnlPopup.style.display = 'none'; if(pnlPopup.iFrame) { pnlPopup.iFrame.style.display = "none"; } }; mainForm.AttachPopup = function() { /// <summary> /// Attach the event handlers for the popup /// </summary> this._scrollHandler = Function.createDelegate(this, this.onUpdating); this._resizeHandler = Function.createDelegate(this, this.onUpdating); $addHandler(window, 'resize', this._resizeHandler); $addHandler(window, 'scroll', this._scrollHandler); this._windowHandlersAttached = true; }; mainForm.DetachPopup = function() { /// <summary> /// Detach the event handlers for the popup /// </summary> if (this._windowHandlersAttached) { if (this._scrollHandler) { $removeHandler(window, 'scroll', this._scrollHandler); } if (this._resizeHandler) { $removeHandler(window, 'resize', this._resizeHandler); } this._scrollHandler = null; this._resizeHandler = null; this._windowHandlersAttached = false; } }; mainForm.CleanUp = function() { /// <summary> /// CleanUp all resources held by mainForm object /// </summary> this.DetachPopup(); var pnlPopup = $get(this.pnlPopup); if(pnlPopup && pnlPopup.iFrame) { pnlPopup.parentNode.removeChild(pnlPopup.iFrame); pnlPopup.iFrame = null; } this._scrollHandler = null; this._resizeHandler = null; this.pnlPopup = null; this.innerPopup = null; this.updating = null; }; mainForm.GetClientBounds = function() { /// <summary> /// Gets the width and height of the browser client window (excluding scrollbars) /// </summary> /// <returns type="Sys.UI.Bounds"> /// Browser's client width and height /// </returns> var clientWidth; var clientHeight; switch(Sys.Browser.agent) { case Sys.Browser.InternetExplorer: clientWidth = document.documentElement.clientWidth; clientHeight = document.documentElement.clientHeight; break; case Sys.Browser.Safari: clientWidth = window.innerWidth; clientHeight = window.innerHeight; break; case Sys.Browser.Opera: clientWidth = Math.min(window.innerWidth, document.body.clientWidth); clientHeight = Math.min(window.innerHeight, document.body.clientHeight); break; default: // Sys.Browser.Firefox, etc. clientWidth = Math.min(window.innerWidth, document.documentElement.clientWidth); clientHeight = Math.min(window.innerHeight, document.documentElement.clientHeight); break; } var scrollLeft = (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft); var scrollTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop); return new Sys.UI.Bounds(scrollLeft, scrollTop, clientWidth, clientHeight); }; if(typeof(Sys) !== "undefined")Sys.Application.notifyScriptLoaded();
Page:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Theme="Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="SM" runat="server"> <Scripts> <asp:ScriptReference Path="~/Scripts/Script.js" /> </Scripts> </asp:ScriptManager> <div style="text-align:center"> <asp:UpdatePanel runat="server" ID="UP"> <ContentTemplate> <p>Click on any button to initiate a assynchronous postback.</p> <p>During postback, a progress script will block any controls on a page so the user can not click any of the screen controls while postback is in progress.</p> <p>Try to resize or scroll the screen. You will notice that controls are still blocked, and progress div changes it's position to stay in the center of the screen</p> <asp:Button runat="server" Text="Postback!" ID="Button1" OnClick="Delay" /><br /> <asp:Button runat="server" Text="Postback!" ID="Button2" OnClick="Delay" /><br /> <asp:Button runat="server" Text="Postback!" ID="Button3" OnClick="Delay" /><br /> <asp:Button runat="server" Text="Postback!" ID="Button4" OnClick="Delay" /><br /> </ContentTemplate> </asp:UpdatePanel> </div> <div id="pnlPopup" class="PrProgress" style="display: none;"> <div id="innerPopup" class="PrContainer"> <div class="PrHeader"> Loading, please wait...</div> <div class="PrBody"> <img width="220px" height="19px" src="App_Themes/Default/Images/activity.gif" alt="loading..." /> </div> </div> </div> </form> <script type="text/javascript"> Sys.Application.add_load(applicationLoadHandler); Sys.Application.add_unload(applicationUnloadHandler); Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler); Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequestHandler); </script> </body> </html>
That's it.
Hope this helps.
hi,
ReplyDeleteIts nice article, solved my big problem. but how to deal with multiple frames page, as I found that only one frame is getting protected from multiple postbacks!
thanks,
Amol.
amol@retailrealm.co.uk
Hi Amol,
ReplyDeleteYou should place the code to every page that is loaded into frames.
Actually I use this progress indicator in multiframe application and it works fine.
Also don't forget to specify correct DocType on the pages.
Why does the DocType matter with this? We noticed when we changed the docType that our scroll bars that had been located inside of a div tag in the middle of our page suddenly vanished and became the scroll bar for the entire page.
ReplyDeleteIt doesn't works in Firefox.
ReplyDeleteHie,
ReplyDeleteThis is a very cool thing to use.
But to my find out, it only works in IE. is there any chances to allow it to work in Firefox?
Hi,
ReplyDeletewould this works in FireFox? i couldnt seems to get it work in Firefox here.
Thanks
Rave
Hi Chin Song,
ReplyDeletethe sample page works in firefox, does it for you ?
http://devarchive.net/update-progress-indicator.aspx
It works with FF if you create a file called "nothing.txt" along your aspx file. That did the work for me.
ReplyDeleteHello,
ReplyDeletehow I can use this code in a master page? I have problem getting the pnlPopup control.
Thanks
Hello,
ReplyDeletehow I can use this code in a master page? I have problem getting the pnlPopup control.
Thanks
Hi There,
ReplyDeleteI have two update panels on my page. I want this progress bar to be displayed upon updation of only one update panel. 2nd one containts my add rotator control so obiviously I dont want this progress panel to be displayed.
This is very urgent so your quick response is highly appreciated.
Regards,
Faisal Fareed
Hi Faisal,
ReplyDeletePlease see documentation for beginRequest event args (http://www.asp.net/ajax/documentation/live/ClientReference/Sys.WebForms/BeginRequestEventArgsClass/default.aspx )
there is a way to get a reference to element that initiated a postback (up to docs) - I believe you can get the id of an element and compare it ith id of update panel - if id starts with id of update panel - than that panel is being updated and you can ignore that in the handler.
Best regards,
Kirill
Nice post buddy, helped me a lot.
ReplyDeleteOne more suggestion.
Here in your example, we need to include file name 'nothing.txt' in the application folder.
Things going in right way when we execute on IE, it won't on FF.
Kindly add that info on your post.
Thanks
How can I use this on a page load
ReplyDelete