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!
Comments
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
You've 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 Microsoft's 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 won't 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 I'd love to see a more web standards-based approach to doing these fancy things.
Kind regards...
too much chatter and not enough demo's. do you blog, or do you program?
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
This is seriously one of my favorite .Net blogs. I check the RSS at least once a week.
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.
I found this thru ScottGu's posts. Nice posts that I can learn from. I too miss jacat's point. Seems like you're a coder who enjoys sharing what he knows/learns. Thanks.
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.
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.
You rock! I like what you're 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
Thanks so much for sharing your knowledge! It's truly appreciated by all the geeks of the world
Hi,
Thanks for the great work. There's one problem though. If any exception occurs during the asyncpostback i get a messagebox shown to the user but the progress image doesn't go away. So is there a way to hide it from the server in an exception scenario?
////////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 clientid's.
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
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
Hi... i had been using your control and it's work fine. But i'm 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
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.
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.