YUI Style AJAX Progress Indicator

If you follow my blog, you have no doubt noticed that I have been taking a tour through the Yahoo! User Interface Library (you can read my previous posts here, here and here).  Well, I think I have finally made my way through a majority of the content and feel like I have come out with a few new UI components that I can incorporate into my current web app.  But before I move on, I thought I would write one last brief post describing how you can incorporate the YUI style progress panel into your existing ASP.NET AJAX web application.

Live Demo (FF, IE6 and IE7) | Download

The markup for the progress panel is below. 

<asp:Panel ID="pnlPopup" runat="server" CssClass="progress" style="display:none;">
    <div class="container">
        <div class="header">Loading, please wait...</div>
        <div class="body">
            <img src="img/activity.gif" />
        </div>
    </div>
</asp:Panel> 

I am making use of 4 style classes: progress, container, header and body.  Below are the style classes and a screen shot with the corresponding element highlighted in blue (I used the IE Developer Toolbar to take the screenshots.  If you haven't downloaded this tool, you should do it now).  You can view the complete stylesheet definition here.  

This is the animated gif I am using for my progress indicator.   

If you don't care for it you should be able to replace this with one of your liking (try googling 'AJAX Progress Indicators')   

 

For this sample, I also incorporated a technique I described here that allows you to render the progress panel directly over a specific control.  To accomplish this, I am calculating the center of the control and manually placing the progress panel over the center of the rendered GridView.  I make this calculation using the OnUpdating and OnUpdated animations of the UpdatePanelAnimationExtender.  During OnUpdating I first fetch the progress panel and a reference to the GridView using the $get shortcut function.  Once I have the reference I use the DomElement classes getBounds function to get the coordinates that make up the boundary.  Then I do a little math to determine where to position the progress.  Here are the OnUpdating and OnUpdated functions ...

function onUpdating(){
    // get the update progress div
    var pnlPopup = $get('<%= this.pnlPopup.ClientID %>'); 

    //  get the gridview element        
    var gridView = $get('<%= this.gvCustomers.ClientID %>');
    
    // make it visible
    pnlPopup.style.display = '';        
    
    // get the bounds of both the gridview and the progress div
    var gridViewBounds = Sys.UI.DomElement.getBounds(gridView);
    var pnlPopupBounds = Sys.UI.DomElement.getBounds(pnlPopup);
    
    //  center of gridview
    var x = gridViewBounds.x + Math.round(gridViewBounds.width / 2) - Math.round(pnlPopupBounds.width / 2);
    var y = gridViewBounds.y + Math.round(gridViewBounds.height / 2) - Math.round(pnlPopupBounds.height / 2);        

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

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

That's it.  Enjoy!


TrackBack

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

Listed below are links to weblogs that reference YUI Style AJAX Progress Indicator:

» YUI Progress Panel In asp.net from DotNetKicks.com
You've been kicked (a good thing) - Trackback from DotNetKicks.com [Read More]

» ASP.NET AJAX Progress Indicator with Real-Time Search Functionality - YUI Style from David Hayden - Florida .NET Developer - C# and SQL Server
[Read More]

» ASP.NET AJAX Progress Indicator with Real-Time Search Functionality - YUI Style from David Hayden - Florida .NET Developer - C# and SQL Server
[Read More]

Comments


Posted by: DaveZ on October 16, 2007 12:00 AM

Matt, thank you for all the posts. They have been extremely helpful and written so that I can understand them ;) I plan to implement these topics into my current project. Thanks again.

Matt,
You rock seriously though you should be up for a MVP award this year.

- Tim

Youve been making some quality posts lately, dude! I like what you are doing with GridViews. I showed an example to my boss and his eyes lit up like flood lights.

I do have a couple issues with some of your examples, though. First of all, display:none really should be defined in the "progress" css class, rather than an inline attribute of the DIV. Oh, and that animated image definitely needs an ALT attribute. And while I am not as familiar with Microsofts AJAX control kit as I should be, I am a firm believer that all Javascript should reside in an external file, rather than part of the markup. However, that wont be possible with this example becuase you are using the server-side scriptlets to get the ClientID of a couple elements.

Your posts are wonderful, but Id love to see a more web standards-based approach to doing these fancy things.

Kind regards...

Posted by: jacat on October 16, 2007 12:00 AM

too much chatter and not enough demos. do you blog, or do you program?

Posted by: Mike on October 16, 2007 12:00 AM

Is it possible to disable the grid during the loading?

@DaveZ, @Tim -

Thanks for the feedback. I really appreciate it.

@Josh -
Great feedback. You are right on all 3 counts.

@jacat -
am I not getting the sarchasim?

@Mike -
Yes. You can try using one of the following 2 approaches (here or here)

Matt

Nice work dude!

But as mentioned in article (http://mattberseth.com/blog/2007/08/updatepanelanimationextender_o.html), the animation will play for every postback, even if its not required. I have a small trick to overcome this and this is how I modified you javascript code


// get the id of the control which caused the postback

var postBackElementID;
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(InitializeRequestHandler);
function InitializeRequestHandler(sender, args) {
postBackElementID = args.get_postBackElement().id.substring(args.get_postBackElement().id.lastIndexOf(_) + 1);
}
function onUpdating(){
// compare to the controlId for which you want to play the animation
if (postBackElementID == btnSearch) {
// your code to display the animation
}
}

function onUpdated() {
if (postBackElementID == btnSearch) {
// your code to stop the animation
}
}

Note: One thing that we need to make sure is, the asp.net controls should not contain a _ character in the ID.

Thanks

Posted by: Jeremy on October 18, 2007 12:00 AM

This is seriously one of my favorite .Net blogs. I check the RSS at least once a week.

Posted by: Shaun Allcock on October 26, 2007 12:00 AM

I am not too familier with JS but how would I display the progress popup in the centre of the screen rather than grid since centre of the grid could often be out of sight.

Posted by: davey on October 26, 2007 12:00 AM

I found this thru ScottGus posts. Nice posts that I can learn from. I too miss jacats point. Seems like youre a coder who enjoys sharing what he knows/learns. Thanks.

Posted by: sinan on November 3, 2007 12:00 AM

Thank you

Thanks for this post. Is this $get(); still working if I want to put the javascript in a JS file. I modified the JS so that I can use it in master page by passing parameters for the popup and the gridview or any other controls.

Posted by: Leland Clemmons on November 12, 2007 12:00 AM

It works perfectly in Safari 3 for Mac. Looks very sleek!

hi, this is great work and I quite enjoy the demo.
However, when implementing on my webs app, I used master page so I need to put the Javascript code into seperate file, but when I put a break point into the JS code, I found out that the function $get return nothing, (notice that I m using vb so I changed this.gridview1 to me.gridView1).
Can you give me some suggestion please, thanks for your help

i v downloaded code demo and it works fine and very helpfull.

Posted by: romulo on December 13, 2007 12:00 AM

You rock! I like what youre applying in the .net to make it look like a YUI interface!

One question, how can I place the javascript in a Master page?

Will var gridView = $get(); work inside master page?

Thanks!

Matt, your work is just incredible. Mostly I donīt even have the ideas to combine design perspectives of other sites into ASP.NET-Controls (especially when itīs about Ajax), but youīre far over that level. So thank you very much for inspiring me each and every week

Posted by: willyT on February 1, 2008 12:00 AM

Thanks so much for sharing your knowledge! Its truly appreciated by all the geeks of the world

Posted by: Rkay on February 13, 2008 12:00 AM

Hi,
Thanks for the great work. Theres one problem though. If any exception occurs during the asyncpostback i get a messagebox shown to the user but the progress image doesnt go away. So is there a way to hide it from the server in an exception scenario?

Posted by: Ankush sarna on February 18, 2008 12:00 AM

////////export data in to textfile ///////////

String strDestinationFile;
strDestinationFile = "C:\Report.txt";
TextWriter tw = new StreamWriter(strDestinationFile);
//writing the header
tw.Write("Master Capital Services Limited".PadLeft(50));
tw.WriteLine();
tw.Write("Holding Summary: From:31/03/2008 Trades Upto:31/03/2008 Transactions Upto:31/03/2008");
tw.WriteLine();
tw.Write("Page No:1 Date:15/02/2008".PadLeft(40));
tw.WriteLine();
tw.Write("------------------------------------------------------------------------------------");
tw.WriteLine();
tw.Write(GridView1.Columns[0].HeaderText.PadRight(15));
tw.Write(GridView1.Columns[1].HeaderText.PadRight(17));
tw.Write(GridView1.Columns[2].HeaderText.PadRight(27));
tw.Write(GridView1.Columns[3].HeaderText.PadRight(15));
tw.Write(GridView1.Columns[4].HeaderText.PadRight(15));
tw.WriteLine();
tw.Write("-------------------------------------------------------------------------------------");
tw.WriteLine();


//writing the data
for (int x = 0; x
{
tw.Write("-------------------------------------------------------------------------------------");
tw.WriteLine();
tw.Write(GridView1.Rows[x].Cells[0].Text.PadRight(15));
tw.Write(GridView1.Rows[x].Cells[1].Text.PadRight(17));
tw.Write(GridView1.Rows[x].Cells[2].Text.PadRight(27));
tw.Write(GridView1.Rows[x].Cells[3].Text.PadLeft(10));
tw.Write(GridView1.Rows[x].Cells[4].Text.PadLeft(10));
tw.WriteLine();
}
tw.Close();
}

Hi Matt, I have multiple grids on a page and of course all onUpdating calls fired at once. I have a workaround for this.

Put the onupdating function in a separate js file, and give it 2 parameters, the grid and the popup clientids.
In the onload of either the page (or, as in my case in the usercontrol), replace the string in the OnUpdating Animation calling onUpdating() with
onUpdating(grid.ClientID, popup.ClientID);

In that master page, add the following javascript:
var callingOject = ;
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(function (sender, args)
{
callingObject = args.get_postBackElement().id;
});

now you can check if callingObject equals the grid.CLientID in the javascript onUpdating function!

P.S. My solution is a slightly more robust (no fixed id strings in JavaScript) of the solution Mike posted

Posted by: paul on April 9, 2008 12:00 AM

Hi Mike
Can you please tell me how to load progress bar on webpart verb click..
i am having trouble , that when i click webpart verb i get args.get_postBackElement().id as zone id, but if i modify it to webpart name it doesnt work...

for each webpart in a zone, i need to have progress bar placed in corresponding webpart when clicking webpart verb..

Let me know if there is work around

thanks
Paul

Posted by: Erick on May 2, 2008 12:00 AM

Hi... i had been using your control and its work fine. But im having a little trouble... when i put a try catch into the event that the button runs, and if it fails... the animation still appears... what could i put in catch section tu stop animation... Thanks

Posted by: Vasudevan on June 12, 2008 12:00 AM

Hi... thanks. it works great for me. I have one problem on my implmentation, after the modelpopup is executed, i have a please help me on this.

Posted by: Nisar Khan on July 11, 2008 12:00 AM

Matt,
is there a way to avoid using
System.Threading.Thread.Sleep(3000); ?

i mean why would you hardcode the sleep time, the time should be based on the response of your server is that correct?

i mean if my query runs more then 3000 then what?

please advice.

thanks, great work man.

note: if possible please email me.

Posted by: sdin on August 7, 2008 10:37 AM

Replace all progroress control IDs as following
$find('ProgressControl13')
with
$find('')

Because masterpage adds ctl00_ContentPlaceHolder1_ in the ID of ProgressControl13

while us $find('mdp') as is.

Matt, your tutorials are amazing.

That said, you should include the updates to this in the project files. I spent a lot of time adding together the different pieces of what was said in the comments to get a working solution...


I added one more customization, the ID of the control to center on. We don't always want to center on a button, usually it is it's parent or perhaps something entirely different.

Here is my javascript in my master page, INSIDE the script manager control tag.

[javascript]
// get the id of the control which caused the postback
var callingObject = "";
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(function (sender, args)
{
callingObject = args.get_postBackElement().id;
});

function onUpdating(senderID, popID, centerCtrlID)
{
// make sure this is the correct element (bug in ajax)
if (callingObject == senderID) {

// get the update progress div
var pnlPopup = $get(popID);

// get the element to center
var ctrl = $get(centerCtrlID);

// make pop visible
pnlPopup.style.display = '';

// get the bounds of both the ctrl and the progress div
var ctrlBounds = Sys.UI.DomElement.getBounds(ctrl);
var pnlPopupBounds = Sys.UI.DomElement.getBounds(pnlPopup);

// center of ctrl
var x = ctrlBounds.x + Math.round(ctrlBounds.width / 2) - Math.round(pnlPopupBounds.width / 2);
var y = ctrlBounds.y + Math.round(ctrlBounds.height / 2) - Math.round(pnlPopupBounds.height / 2);

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

function onUpdated(elementID, popID)
{
if (callingObject == elementID) {
// get the update progress div
var pnlPopup = $get(popID);
// make it invisible
pnlPopup.style.display = 'none';
}
}
[/javascript]

------------------------

Here are the scipt actions form in my update panel extender in my content page (I am using your slider control). This can be added to any panel on the page, just change the control id's:

[OnUpdating]

ScriptAction Script="onUpdating('ctl00_cphBody_listview_pager_ctl00_txtSlider', 'ctl00_cphBody_pnlPopup', 'ctl00_cphBody_UpdatePanel);"

[/OnUpdating]


[OnUpdated]

ScriptAction Script="onUpdated('ctl00_cphBody_listview_pager_ctl00_txtSlider', 'ctl00_cphBody_pnlPopup');"

[/OnUpdated]

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

  • Justin Moses wrote: Matt, your tutorials are amazing. That said, you should include the updates to this in the project ...
  • sdin wrote: Replace all progroress control IDs as following $find('ProgressControl13') with $find('') Because...
  • Nisar Khan wrote: Matt, is there a way to avoid using System.Threading.Thread.Sleep(3000); ? i mean why would you har...
  • Vasudevan wrote: Hi... thanks. it works great for me. I have one problem on my implmentation, after the modelpopup is...
  • Erick wrote: Hi... i had been using your control and its work fine. But im having a little trouble... when i put ...
  • paul wrote: Hi Mike Can you please tell me how to load progress bar on webpart verb click.. i am having trouble ...
  • Colin Dekker wrote: Hi Matt, I have multiple grids on a page and of course all onUpdating calls fired at once. I have a ...
  • Colin Dekker wrote: P.S. My solution is a slightly more robust (no fixed id strings in JavaScript) of the solution Mike ...