Introduction
Problem
One of the biggest problems in the web is pages that take a long time to process once submitted. Let’s say you have an ASP.NET form that takes up to 30 seconds to process and the user keeps pushing the submit button twice or more hoping to get the information faster (which can cause data problems). One way to solve this problem is by disabling the submit button once it’s been pushed. But what if you have more than one button on your form?
Solution
In this article, I will show you how you can disable all your ASP.NET form's controls during a post back and also show the user a nice friendly animated GIF while the page is posting back. In fact, you can even move this little box if you are bored waiting for it.
Yahoo to Yahoo
Yahoo gives us a full working framework of JavaScript that we can download and use in our web applications for free! So why not take advantage of it? You can find more information about it here.
In this article, I will only use the Panel
object from the Yahoo YUI. Here are a few easy steps to get started:
Download the framework scripts to your project from here (v. 2.7).
The framework should be in one directory called YUI (I have downloaded the 2.7.0 version). Copy this directory to your web project, your web project should look like this:
Show Me the Money Jerry!
Now that we have the Yahoo Framework setup in our project, we are in business! Here are a few easy steps to setup your ASP.NET page to take full advantage of the Panel
object (here).
Under the <head>
tag of HTML, include these JavaScript files:
<!---->
<link rel="stylesheet" type="text/css" href="yui/build/container/assets/container.css"/>
<link rel="stylesheet" type="text/css" href="yui/build/menu/assets/skins/sam/menu.css"/>
<!---->
<script type="text/javascript" src="yui/build/utilities/utilities.js" ></script>
<script type="text/javascript" src="yui/build/container/container-min.js"></script>
<script type="text/javascript">
Let’s create few easy JavaScript functions: let’s start with initializing the Panel
with a title that says "Loading, Please wait…" and have an animated GIF called Wait.gif (you can add more properties to this object, read the Yahoo docs).
function InitDialogs() {
DialogBox_Loading = new YAHOO.widget.Panel("waitBox",
{ fixedcenter: true, modal: true, visible: true,
width: "230px", close: false, draggable: true });
DialogBox_Loading.setHeader("Loading, please wait...");
DialogBox_Loading.setBody('<div style="text-align:center;">
<img src="images/Wait.gif" id="Image1" /></div>');
DialogBox_Loading.render(document.body);
}
Let’s create a JavaScript function that is responsible to show the “wait box” or hide it based on a boolean value. We also want to make sure that the ASP.NET page is valid (all ASP.NET validation controls have succeeded) before we show the Panel
object. We can use the Page_IsValid
flag on the client side to check that. In order to get this flag, we are forced to call the JavaScript method generated by .NET called Page_ClientValidate();
on the push of the button. I will show this later in the article.
function Loading(b) {
if (b == true && Page_IsValid == true) {
DialogBox_Loading.show();
}
else {
DialogBox_Loading.hide();
}
}
For this example, I have added the AJAX script manager so I can enjoy the pageLoaded()
event on the client side. To read more about it, go here. If you don't want to use the Ajax Framework, then we need to wire up the page load event in JavaScript ourselves. Here is an example of how to do it: Let's add a helper JavaScript function that will call any function we want for a page load event. I have included that sample in my download sample project under YahooWaitLoadOnButtonServerNoAjax.aspx. Here is a working example of how to do it with JavaScript:
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(function() {
pageLoad();
})
In the Page Load event, I will initialize the Dialog box and not show it:
function pageLoad() {
InitDialogs();
Loading(false);
}
Now we are ready to create a few ASP.NET controls, let’s create a text box, a Required Field Validator and an ASP.NET button that takes more than 30 seconds to process. We are going to link a few JavaScript calls to our button.
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="false" />
<div>
<asp:TextBox ID="txtFirstName" runat ="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="VtxtFirstName" ControlToValidate="txtFirstName"
ErrorMessage="error" runat="server"></asp:RequiredFieldValidator>
<asp:Button ID="btnPushLongJob" Text ="Start Long Job" runat="server"
OnClientClick="Page_ClientValidate();Loading(true);" OnClick="btnPushLongJob_Click"/>
</div>
</form>
</body>
I am calling Page_ClientValidate()
which is a JavaScript function generated by my ASP.NET Validator control. I was forced to call it so it can set the Page_isValid
flag on the client side which is used in Loading
JavaScript function. And I am calling Loading(true)
to show the Dialog box.
Now let’s plug a long processing task in our code behind for the event of Onclick
of the button (remember to add the System.Threading
namespace to enjoy the Thread
class).
protected void btnPushLongJob_Click(object sender, EventArgs e)
{
Thread.Sleep(30000);
}
Problem: GIF Animation Stops during Postbacks
Well, sometimes life is hard and not everything works as expected. For some reason, Internet Explorer decided to make our life a bit harder and stop all GIF animations during a post back, but there is a way around it and I will show it to you right here and now for free (I am a nice guy, no?). Resetting the source of the image in JavaScript seems to fix this issue.
I have added the following JavaScript code:
function UpdateImg(ctrl, imgsrc) {
var img = document.getElementById(ctrl);
img.src = imgsrc;
}
And I link my ASP.NET button to it from the code behind in the Page Load event.
protected void Page_Load(object sender, EventArgs e)
{
btnPushLongJob.Attributes.Add("onclick",
"setTimeout(\"UpdateImg('Image1','images/Wait.gif');\",50);");
}
And we are done!
Here is a full page code:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="YahooWaitLoadOnButtonServerSide.aspx.cs"
Inherits="YahooWaitLoadOnButtonServerSide" %>
<!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></title>
<!---->
<link rel="stylesheet" type="text/css" href="yui/build/container/assets/container.css"/>
<link rel="stylesheet" type="text/css" href="yui/build/menu/assets/skins/sam/menu.css"/>
<!---->
<script type="text/javascript" src="yui/build/utilities/utilities.js" ></script>
<script type="text/javascript" src="yui/build/container/container-min.js"></script>
<script type="text/javascript">
function pageLoad() {
InitDialogs();
Loading(false);
}
function UpdateImg(ctrl, imgsrc) {
var img = document.getElementById(ctrl);
img.src = imgsrc;
}
function InitDialogs() {
DialogBox_Loading = new YAHOO.widget.Panel("waitBox",
{ fixedcenter: true, modal: true, visible: true,
width: "230px", close: false, draggable: true });
DialogBox_Loading.setHeader("Loading, please wait...");
DialogBox_Loading.setBody('<div style="text-align:center;">
<img src="images/Wait.gif" id="Image1" /></div>');
DialogBox_Loading.render(document.body);
}
function Loading(b) {
if (b == true && Page_IsValid == true) {
DialogBox_Loading.show();
}
else {
DialogBox_Loading.hide();
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="false" />
<div>
<asp:TextBox ID="txtFirstName" runat ="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="VtxtFirstName"
ControlToValidate="txtFirstName" ErrorMessage="error"
runat="server"></asp:RequiredFieldValidator>
<asp:Button ID="btnPushLongJob" Text ="Start Long Job" runat="server"
OnClientClick="Page_ClientValidate();Loading(true);" OnClick="btnPushLongJob_Click"/>
</div>
</form>
</body>
</html>
And here is the full code for the Code behind file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
public partial class YahooWaitLoadOnButtonServerSide : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
btnPushLongJob.Attributes.Add("onclick",
"setTimeout(\"UpdateImg('Image1','images/Wait.gif');\",50);");
}
protected void btnPushLongJob_Click(object sender, EventArgs e)
{
Thread.Sleep(3000);
}
}
The Code
I have created a sample project that includes the Yahoo YUI 2.7 Framework. You would want to try the YahooWaitLoadOnButtonServerSide.aspx page for this sample (for no Ajax support, view YahooWaitLoadOnButtonServerNoAjax.aspx page). I have also included a few other samples like a tool tip and using the Dialog box with Page Methods.
You can download the code from the link at the top of this article.
I hope you enjoyed this article, and it made your life a little bit easier.