Disable UpdatePanel Contents During Async PostBack

About a month ago I wrote a post describing how an UpdatePanel could be used to enhance the regular asp:Wizard control.  In response to this post, Bilal posted the following comment

Is there a good way to disable the wizard control when the updateprogress is showing and not only fade it out?

Live Demo 1 | Live Demo 2 | Live Demo 3Download

[Update: 8/9/2007] I updated the sample site, download and code samples to include the trailing 'px' when setting the width/height so it would work with FireFox.

[Update 8/6/2007] I followed a Ryan and MichaelD's advice and converted this example into an extender control.  You can view the posting here.  This posting also provides an interactive demo and the full source code.  It also fixes the FireFox problem.

I hadn't tried this before, but I can see how it would be useful.  In the web application I am currently working on, we have a number of pages with GridViews that are contained within UpdatePanels and searching, sorting or paging can take up to five seconds depending on the current load.  During that time we display a progress indicator, but we typically do not disable the GridView.  As a result, all of the controls within the GridView also remain enabled and mousing over them gives the indication that they can be used (the mouse glove is displayed).  I assume Bilal is running into a similar problem with the Wizard. 

An even worse scenario is one where the UpdatePanel contains input elements the user modifies while the asynchronous request is executing.  Because the response overwrite the DOM, any changes made by the user are lost when the request finishes executing.  The following live demo shows this.  The demo page consists of an input box and a button, both contained within an UpdatePanel.  Clicking the button triggers the panel to update (it takes 10 seconds).  Any changes that are made to the textbox by the user during the async postback will be lost when the request completes.  You can try it out for yourself.

My first stab at solving this was to use the EnableAction provided by the UpdatePanelAnimationExtender.  Using this I could easily disable the GridView in the OnUpdating animation and re-enable it during OnUpdated.  While this would work, there is nothing visually appealing about a disabled GridView ...

My next thought was to see how the ModalPopupExtender manages to disable all of the controls on the page, yet still keeps the page visually appealing.  After browsing through the source code, it turns out this is accomplished by placing a div over the 'disabled' area and set its z-order to be the top most.  This is nice because it provides the required functionality and allows for customizing exactly what a disabled area looks like by setting the style on the div.  Here are two live demo's that use this technique.

Live Demo 1 | Live Demo 3

Below are the steps I took to create these samples.

Create the Style for the Disabled DIV

I like a light gray background that is almost trasparent.  Here is the style I am using for this.

.background {
    background-color:gray; 
    filter:alpha(opacity=10); 
    opacity:0.1; 
} 

Create the Progress DIV

Next, I add the div that I want displayed during async postbakcs as a progress indicator.  I personally like the google analyitics style indicator, so that is what I am using here.  You can view another example of this here.

Here is the markup for this element.

<div id="updateProgressDiv" class="updateProgress" style="display:none">
    <div align="center" style="margin-top:13px;">
        <img src="Img/simple.gif" />
        <span class="updateProgressMessage">Loading ...</span>
    </div>
</div>

Implement pageLoad and Hook into the beginRequest and endRequest Events

Next we add the pageLoad javascript function to the page.  Then we add a handler for the PageRequestManagers beginRequest and endRequest events.  We also cache references to both the GridView and the progress div element.  Finally, we create the background div element and add it to the page.  When creating the div, we also initialize the zIndex to 1000 and set the className property to the style we want to apply to it.  Setting the zIndex will ensure this element is stacked above the GridView.

var _updateProgressDiv;
var _backgroundDiv;
var _gridView;

function pageLoad(sender, args){    
    //  register for our events
    Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequest);
    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);    
    
    //  get the updateprogressdiv
    _updateProgressDiv = $get('updateProgressDiv');
    //  fetch the gridview
    _gridView = $get('<%= this.gvCustomers.ClientID %>');
    
    //  create the div that we will position over the gridview
    //  during postbacks
    _backgroundDiv = document.createElement('div');
    _backgroundDiv.style.display = 'none';
    _backgroundDiv.style.zIndex = 10000;
    _backgroundDiv.className = 'background';
    
    //  add the element to the DOM
    _gridView.parentNode.appendChild(_backgroundDiv);
} 

Implement beginRequest

Now we can implement the beginRequest javascript method.  beginRequest will be invoked just before the async request is made, so this is where we will display our progress indicator and place our disabled div over the GridView.  To do this we first need to do a little math to figure out where the center of the GridView is as well as what its height and width are.  Once this is done we place the progress indicator in the center of the GridView and place the disabled div over the GridView.

function beginRequest(sender, args){
    // make it visible
    _updateProgressDiv.style.display = '';             
    _backgroundDiv.style.display = '';
    
    // get the bounds of both the gridview and the progress div
    var gridViewBounds = Sys.UI.DomElement.getBounds(_gridView);
    var updateProgressDivBounds = Sys.UI.DomElement.getBounds(_updateProgressDiv);
               
    //  center of gridview
    var x = gridViewBounds.x + Math.round(gridViewBounds.width / 2) - Math.round(updateProgressDivBounds.width / 2);
    var y = gridViewBounds.y + Math.round(gridViewBounds.height / 2) - Math.round(updateProgressDivBounds.height / 2);        
    
    //  set the dimensions of the background div to the same as the gridview
    _backgroundDiv.style.width = gridViewBounds.width + 'px';
    _backgroundDiv.style.height = gridViewBounds.height + 'px';              

    //    set the progress element to this position
    Sys.UI.DomElement.setLocation(_updateProgressDiv, x, y);     
    //  place the div over the gridview
    Sys.UI.DomElement.setLocation(_backgroundDiv, gridViewBounds.x, gridViewBounds.y);           
}

Implement endRequest

Finally for the last piece - just a little clean up.  In endRequest (which is invoked after the async request finishes executing) we hide the disabled div as well as the progress indicator.

function endRequest(sender, args) {
    // make it invisible
    _updateProgressDiv.style.display = 'none';
    _backgroundDiv.style.display = 'none';
}
 

Thats it.  Enjoy!


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/50

Listed below are links to weblogs that reference Disable UpdatePanel Contents During Async PostBack:

» August 2nd Links: ASP.NET AJAX and the ASP.NET AJAX Control Toolkit from ScottGu's Blog
Here is the latest in my semi-regular link-listing series . Today's links are all about ASP.NET AJAX [Read More]

» August 2nd Links: ASP.NET AJAX and the ASP.NET AJAX Control Toolkit from ASP.Net Resources
Here is the latest in my semi-regular link-listing series . Today's links are all about ASP.NET AJAX [Read More]

» Doppel Klick bei Submit-Button verhindern from Verstehe.
Doppel Klick bei Submit-Button verhindern - Doppelter Postback verhindern [Read More]

Comments


Hi Matt,
while your sample works great in IE, Firefox still happily executes the hyperlinks.

You should totally make this an AjaxToolkit Extender. :)

Posted by: Dave on August 3, 2007 12:00 AM

I couldnt get any of the Live Demos to work with the latest edition of Firefox. I could click on the hyperlinks in the first demo and edit the text in the second when the loading message was displayed :(

Posted by: Ambrose Anandraj on August 6, 2007 12:00 AM

Hi

This is good. But the Filter will not work in the Netscape. When we say Ajax will work in all the browsers then the disabling should also work in all browsers. How to implement the disabled in Netscape.

Posted by: Ryan on August 6, 2007 12:00 AM

Ive been looking for something like this for a while now. It really should be an extender. I was able to get it to work with Firefox simply by adding the "px" suffix when specifying the width/height of the _backgroundDiv.

Posted by: Bill on August 6, 2007 12:00 AM

Any chance you can re-post with the fix suggested by Ambrose Anandraj for firefox? I have been messing with it and cant get it right.

@Bill - I moved this into an extender control and in doing so I fixed the issue with FireFox. You can view this sample here: http://mattberseth.com/blog/2007/08/disablecontrolextender.html.

Matt.

Posted by: Bill on August 8, 2007 12:00 AM

Matt,

In firefox the loading gif was not displayed in the right place the very first time the page was async posted. I moved

// make it visible
_updateProgressDiv.style.display = ;
_backgroundDiv.style.display = ;

To the end of the funtion to correct this.

Bill

I just noticed my name in this article :).

Thanks Matt a lot!

Regards

Hmm

I can still use the space and enter key.

If there is a scrollbar, then the loading div is not centered when u scroll.


@bilal -
Thanks for the feedback. I will investigate these issues.

Matt.

Posted by: Jignesh on October 20, 2007 12:00 AM

Hi,

I have added div over div control not on gridview.

Now, on ajax request div is created but after end request
it still visible over page..

so what can i do? pls..reply

Posted by: Tim Payne on December 7, 2007 12:00 AM

Hi Jignesh,

In order to make the above code work with any element work with any element you need to add some extra code.

add:

var _added = false;

to the variable declaration.

change the event adding to:

if (_added == false)
{
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequest);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
_added = true;
}
(this prevents registering the functions multiple times)

change the div creation to:
if (document.getElementById("divDisabler") == null)
{
_backgroundDiv = document.createElement(div);
_backgroundDiv.style.display = none;
_backgroundDiv.style.zIndex = 10000;
_backgroundDiv.className = background;
_backgroundDiv.id = divDisabler;
// add the element to the DOM
_gridView.parentNode.appendChild(_backgroundDiv);
}

(this stops the div getting added more than once, which is what was causing the problem!)

Hope that helps!

Posted by: luis caiano on April 22, 2008 12:00 AM

some, like me might want to use "Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(..)"
instead of "add_endRequest"
so it will only run end, after rendering the callback

Posted by: George Polevoy on October 6, 2008 05:00 PM

the link to the extender version was not working because of the dot at the end of it:

http://mattberseth.com/blog/2007/08/disablecontrolextender.html.

this one works:
http://mattberseth.com/blog/2007/08/disablecontrolextender.html

Posted by: Frederick Ayala on October 21, 2008 12:06 PM

Hi, thanks a lot for your code, it's amazing, easy and very useful. I'm working in add a DisplayAfter to your code.

Great Blog!!!

Posted by: Rupesh kumar Tiwari on October 23, 2008 10:53 AM

Hi, thanks for the helpful posting. But, when I used the code I found two things.
1) When there is ComboBox inside the gridview then it is not disabling the ComboBox. It is enabled and user can edit the ComboBox. I think that z-index of the ComboBox is higher than whatever z-index we are providing i.e. 10000. So, is there any other way to disable ComboBox also?
2) The css propery filter is not working in FireFox. Do we have any other property for the same?
Kindly suggest for the above two issues.

Thanks in advance,
Rupesh kumar Tiwari.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • Rupesh kumar Tiwari wrote: Hi, thanks for the helpful posting. But, when I used the code I found two things. 1) When there is C...
  • Frederick Ayala wrote: Hi, thanks a lot for your code, it's amazing, easy and very useful. I'm working in add a DisplayAfte...
  • George Polevoy wrote: the link to the extender version was not working because of the dot at the end of it: <a href="http...
  • luis caiano wrote: some, like me might want to use "Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(..)" i...
  • Tim Payne wrote: Hi Jignesh, In order to make the above code work with any element work with any element you need to...
  • Jignesh wrote: Hi, I have added div over div control not on gridview. Now, on ajax request div is created but aft...
  • Bilal wrote: Hmm I can still use the space and enter key. If there is a scrollbar, then the loading div is not ...
  • Matt Berseth wrote: @bilal - Thanks for the feedback. I will investigate these issues. Matt. ...