ASP.NET AJAX: Rendering a Gmail-like 'Loading' Indicator over a Specific ASP.NET Control

I came across a blog post discussing a slick way to use the ASP.NET AJAX UpdateProgress control to add a gmail-like progress indicator to an ASP.NET web page.

 

 

 

kick it on DotNetKicks.com

I liked the approach the author used and it clearly works great for scenarios where you want to display a single 'something is happening' message to the user while the page is being updated.  However, after the operation completes and the indicator disappears, it is still up to the user to figure out where on the screen (i.e. what control was updated?) to look for the new changes.  If your screens are relatively simple, or if you feel the update should be obvious this is probably not an issue for you.  Unfortunately things aren't so for the web application I am currently working on.  A few of the screens contain a number of different sections and users would like to see the indicator rendered over the control (most commonly a GridView or DetailsView) that is being updated.

To achieve this, I am using the UpdatePanelAnimationExtender control that is part of the AjaxControlToolkit (You can follow directions here to install and get started using the toolkit).  This control allows for defining the visual effects you want run before (the OnUpdating animation) and after (the OnUpdated animation) the contents within the UpdatePanel have been refreshed.  For the gmail progress indicator, the OnUpdaing animation runs a piece of JavaScript that calculates the bounds of the GridView that is contained within the UpdatePanel and renders an HTML DIV in the upper right hand corner of the GridView control.  After the update occurs, the OnUpdated fires and runs another piece of JavaScript that hides the DIV.        

You can view a live demo here and download the sample web application with all of the code included here.  There is no code-behind for the page, so if you are intereseted in quickly viewing the markup and JavaScript for the page - it is posted below (you will have to change the connection string to point to your copy of the Northwind database ...) 

 

Code sample for this page:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
    <script type="text/javascript" language="javascript">
    
    function onUpdating(){
        // get the update progress div
        var updateProgressDiv = $get('updateProgressDiv'); 

        //  get the gridview element        
        var gridView = $get('<%= this.gvCustomers.ClientID %>');
        
        // make it visible
        updateProgressDiv.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);
        
        var x;
        var y;
        
        //    do the math to figure out where to position the element
        if($get('rdoCenter').checked){
            //  center of gridview
            x = gridViewBounds.x + Math.round(gridViewBounds.width / 2) - Math.round(updateProgressDivBounds.width / 2);
            y = gridViewBounds.y + Math.round(gridViewBounds.height / 2) - Math.round(updateProgressDivBounds.height / 2);        
        }
        else if($get('rdoTopLeft').checked){
            //  top left of gridview
            x = gridViewBounds.x;
            y = gridViewBounds.y;
        }
        else{
            //  top right of gridview
            x = (gridViewBounds.x + gridViewBounds.width - updateProgressDivBounds.width);
            y = gridViewBounds.y;
        }

        //    set the progress element to this position
        Sys.UI.DomElement.setLocation (updateProgressDiv, x, y);           
    }

    function onUpdated() {
        // get the update progress div
        var updateProgressDiv = $get('updateProgressDiv'); 
        // make it invisible
        updateProgressDiv.style.display = 'none';
    }
    
    </script>

</head>
<body>
    <form id="form" runat="server">
        <asp:ScriptManager ID="scriptManager" runat="server" />
        <div>
            <asp:SqlDataSource ID="sqldsCustomers" runat="server" 
                SelectCommand="select customerid, companyname, contactname, contacttitle from dbo.customers"
                SelectCommandType="Text" ConnectionString="todo" />
            <p style="background-color:AliceBlue; width:95%">
                Example of using an UpdatePanelAnimationExtender to place an animated gif over a GridView while the<br /> 
                GridView is being refreshed.  Click the column headers or the paging buttons to cause the grid to refresh<br />
                You can toggle where the animation is to be displayed using the radio buttons<br />
            </p>
            <div>
                <input id="rdoCenter" type="radio" name="location" value="center" checked="checked" />Center
                <input id="rdoTopLeft" type="radio" name="location" value="topleft" />Top Left
                <input id="rdoTopRight" type="radio" name="location" value="topright" />Top Right
            </div>
            <br />
            <br />
            <asp:Label ID="lblTitle" runat="server" Text="Customers" BackColor="lightblue" Width="95%" />
            <asp:UpdatePanel ID="updatePanel" runat="server">
                <ContentTemplate>
                    <asp:GridView ID="gvCustomers" runat="server" AllowPaging="true" AllowSorting="true"
                        PageSize="20" DataSourceID="sqldsCustomers" Width="95%">
                        <AlternatingRowStyle BackColor="aliceBlue" />
                        <HeaderStyle HorizontalAlign="Left" />
                    </asp:GridView>
                </ContentTemplate>
            </asp:UpdatePanel>
            <ajaxToolkit:UpdatePanelAnimationExtender ID="upae" BehaviorID="animation" runat="server" TargetControlID="updatePanel">
                <Animations>
                    <OnUpdating>
                        <Parallel duration="0">
                            <%-- place the update progress div over the gridview control --%>
                            <ScriptAction Script="onUpdating();" />  
                         </Parallel>
                    </OnUpdating>
                    <OnUpdated>
                        <Parallel duration="0">
                            <%--find the update progress div and place it over the gridview control--%>
                            <ScriptAction Script="onUpdated();" /> 
                        </Parallel> 
                    </OnUpdated>
                </Animations>
            </ajaxToolkit:UpdatePanelAnimationExtender>
            <div id="updateProgressDiv" style="background-color:#CF4342; display:none; position:absolute;">
                <span style="color:#fff; margin:3px">Loading ...</span>
            </div>
        </div>
    </form>
</body>
</html>

TrackBack

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

Listed below are links to weblogs that reference ASP.NET AJAX: Rendering a Gmail-like 'Loading' Indicator over a Specific ASP.NET Control:

» Rendering a Gmail 'Loading' Indicator over a Specific ASP.NET Control from DotNetKicks.com
You've been kicked (a good thing) - Trackback from DotNetKicks.com [Read More]

» ASP.NET AJAX: Rendering a Gmail-like 'Loading' Indicator from Emad on Web Technologies
Here is an interesting article on how to display Gmail-like progress indicator: Matt Berseth: ASP.NET [Read More]

» ASP.NET AJAX: Rendering a Gmail-like 'Loading' Indicator from Emad on Web Technologies
http://www.emadibrahim.com/2007/08/04/aspnet-ajax-rendering-a-gmail-like-loading-indicator/ Here is an [Read More]

» ASP.NET AJAX: Rendering a Gmail-like 'Loading' Indicator from Emad on Web Technologies
http://www.emadibrahim.com/2007/08/04/aspnet-ajax-rendering-a-gmail-like-loading-indicator/ Here is an [Read More]

» Microsoft Ajax from Confluence: Software Engineering Univ
BookMarks ASP.NET AJAX Roadmap [Read More]

Comments


Nicely done, I have a different method of doing this and I think its easier/less code (I am lazy)... Check it out at http://www.emadibrahim.com/2007/08/04/aspnet-ajax-rendering-a-gmail-like-loading-indicator/

Posted by: Andrew Cushen on September 16, 2007 12:00 AM

Hey Matt-

Thanks for the code. I have it almost working, but theres one kink: I want the UpdateProgress control to always show up in the center of my GridView, so I removed the if statement around the code that centers the control, and removed the else statements. Unfortunately, Im not getting the results your sample shows: the first time the UpdateProgress control shows, its aligned to the left edge of the GridView. The next load, it moves a bit to the right, and then on the third load, it finally centers.
I have a feeling its related to the fact that I dynamically show one of two GridViews based on a users choice in a radioButtonList. I altered your JavaScript code so that if the variable holding the first gridview is null, it then sets the variable to the second gridview; but Im experiencing the side effects I mentioned above.Any ideas?Thanks,-Andrew

Great idea.
I will try it asap.

Posted by: arup on November 22, 2007 12:00 AM

hi
I want to use this in asp.net
ver1.1 can i do this?

I think the idea is great, doing it in that way, because we can use it in every control of asp.net tech.

Posted by: waqar on December 14, 2007 12:00 AM

when i use this

// get the gridview element
var gridView = $get();

ERORR!
this is not declared whats this?

I think the idea is great, doing it in that way, because we can use it in every control of asp.net tech.

Posted by: smile on March 24, 2008 12:00 AM

Hi Matt,

Great Stuff! Very usable and simple to implement. Thanks a lot man.

Posted by: Anonymous on April 7, 2008 12:00 AM

Does not work with 2 level deep nested UpdatePanels. Do you have any updates to your solution? Would love to have this working with nested UpdatePanels.
Thx

Posted by: RobertC on April 21, 2008 12:00 AM

I found a problem when using this with a page that uses a ModalPopupExtender. After pressing the update button on the ModalPopupExtender update panel, the updateProgressDiv remains hidden underneath the modal popup. Is there some way to force the updateProgressDiv to always be on top?

Thanks,
Robert

Thanks you a lot.

Posted by: Axel on August 18, 2008 03:05 PM

Additionally, if you want to disable the control while the update is taking place do the following:

GridView example


function onUpdating(){
// get the update progress div
var updateProgressDiv = $get('updateProgressDiv');

// get the gridview element
var gridView = $get('');
// disable gridView as well
gridView.disabled = 'true';
// make it visible
updateProgressDiv.style.visibility = 'visible';


// 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);

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 progress element to this position
Sys.UI.DomElement.setLocation (updateProgressDiv, x, y);
}

function onUpdated() {
// get the update progress div
var updateProgressDiv = $get('updateProgressDiv');
// make it invisible
updateProgressDiv.style.visibility = 'hidden';

// re-enable gridview after update if disabled
var gridView = $get('');
gridView.disabled = 'false';

}

FYI, I also changed the display = 'none' or '' to visibility = 'hidden' or 'visible'. This keeps the animated gif from pausing as it does in situations when you set the position attribute to absolute or relative. See my post (last one on page by axeman420) regarding this issue and my findings @ http://forums.asp.net/p/1163169/1928798.aspx

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

  • Axel wrote: Additionally, if you want to disable the control while the update is taking place do the following: ...
  • Prefabrik wrote: Thanks you a lot. ...
  • RobertC wrote: I found a problem when using this with a page that uses a ModalPopupExtender. After pressing the up...
  • Anonymous wrote: Does not work with 2 level deep nested UpdatePanels. Do you have any updates to your solution? Would...
  • smile wrote: Hi Matt, Great Stuff! Very usable and simple to implement. Thanks a lot man. ...
  • chetuo wrote: I think the idea is great, doing it in that way, because we can use it in every control of asp.net t...
  • waqar wrote: when i use this // get the gridview element var gridView = $get(); ERORR!...
  • Arturo wrote: I think the idea is great, doing it in that way, because we can use it in every control of asp.net t...