Click here to Skip to main content
Click here to Skip to main content
Articles » Web Development » Ajax » General » Downloads
 
Add your own
alternative version

Magic AJAX: Applying AJAX to your existing Web Pages

, 28 May 2007
How to apply AJAX technologies to your web pages without replacing ASP.NET controls and/or writing JavaScript code.
magicajax-030-net11.zip
magicajax
Examples
ExampleSite (.NET 2.0 only)
Web.sitemap
webparts
images
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
examples
App_Data
App_Code
Docs
Core
script
bin
MagicAjax.dll
magicajax-030-net20.zip
MagicAjax.dll
Web.sitemap
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
magicajax-030-source.zip
Web.sitemap
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
MagicAjax.snk
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
UI
Design
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Controls
ClientEventControls
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Extra
Entries.Old
Entries
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Interfaces
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Configuration
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
magicajax.zip
AJAXTest
AJAXTest.csproj.webinfo
Global.asax
Ajax
Ajax.csproj.user
Controls
Design
script
using System;
using System.Configuration;
using System.Web;
using System.Web.UI;
using System.Collections;
using Ajax.Controls;

namespace Ajax
{
	/// <summary>
	/// Defines the various CallBack types
	/// </summary>
	public enum CallBackType
	{
		/// <summary>
		/// Client didn't invoke a CallBack
		/// </summary>
		None,
		/// <summary>
		/// Standard CallBack invoked by a control on the page
		/// </summary>
		Control,
		/// <summary>
		/// CallBack invoked because the page appeared on the browser by the Back button
		/// </summary>
		Startup,
		/// <summary>
		/// CallBack invoked by the CallBackTimer
		/// </summary>
		Timer
	}

	/// <summary>
	/// Helper functions for CallBack handling.
	/// </summary>
	public sealed class CallBackHelper
	{
		private CallBackHelper() { }

		#region Static Properties
		/// <summary>
		/// Returns the CallBack type, suitable for a switch block.
		/// </summary>
		public static CallBackType CallBackType
		{
			get
			{
				if ( IsCallBackStartup )
					return CallBackType.Startup;
				else if ( IsCallBackTimer )
					return CallBackType.Timer;
				else if ( IsCallBack )
					return CallBackType.Control;
				else
					return CallBackType.None;
			}
		}

		/// <summary>
		/// Determines whether a CallBack was invoked on the server by the client.
		/// </summary>
		public static bool IsCallBack
		{
			get
			{
				return ( HttpContext.Current != null && HttpContext.Current.Request.Form["__AJAX_EVENTTARGET"] != null );
			}
		}

		/// <summary>
		/// Determines whether the callback occured by a page appearing on the browser by the Back button.
		/// </summary>
		/// <remarks>
		/// See the remarks of the RegisterCallBackStartupScript method.
		/// </remarks>
		public static bool IsCallBackStartup
		{
			get
			{
				return ( HttpContext.Current != null && HttpContext.Current.Request.Form["__AJAX_EVENTTARGET"] == "__AJAX_CALLBACKSTARTUP" );
			}
		}

		/// <summary>
		/// Determines whether the callback occured by the CallBackTimer.
		/// </summary>
		/// <remarks>
		/// See the remarks of the SetCallBackTimerInterval method.
		/// </remarks>
		public static bool IsCallBackTimer
		{
			get
			{
				return ( HttpContext.Current != null && HttpContext.Current.Request.Form["__AJAX_EVENTTARGET"] == "__AJAX_CALLBACKTIMER" );
			}
		}

		/// <summary>
		/// Gets the name of the javascript function that is used for CallBacks from
		/// the client.
		/// </summary>
		public static string CallBackClientFunction
		{
			get { return "AJAXCbo.DoPostCallBack"; }
		}

		/// <summary>
		/// Included for convenience.
		/// </summary>
		public static HttpContext Context
		{
			get
			{
				return System.Web.HttpContext.Current;
			}
		}

		/// <summary>
		/// Included for convenience.
		/// </summary>
		public static HttpResponse Response
		{
			get
			{
				HttpResponse hr = System.Web.HttpContext.Current.Response;
				if (hr == null)
					throw new Exception("CallBackHelper could not access current HttpResponse object");

				return hr;
			}
		}

		/// <summary>
		/// Included for convenience.
		/// </summary>
		public static HttpRequest Request
		{
			get
			{
				HttpRequest hr = System.Web.HttpContext.Current.Request;
				if (hr == null)
					throw new Exception("CallBackHelper could not access current HttpRequest object");

				return hr;
			}
		}
		#endregion

		#region internal Static Properties
		/// <summary>
		/// Gets or sets the Page in session.
		/// </summary>
		internal static Page SessionPage
		{
			get
			{
				return (Page) HttpContext.Current.Session[SessionPageKey];
			}
			set
			{
				HttpContext.Current.Session[SessionPageKey] = value;
			}
		}

		/// <summary>
		/// Gets the session key that will be used to store the page in the session.
		/// </summary>
		/// <remarks>
		/// It uses the RawUrl of the request to distinguish multiple Pages.
		/// </remarks>
		internal static string SessionPageKey
		{
			get
			{
				return String.Format("AJAX_PAGE_{0}", Request.RawUrl);
			}
		}
		#endregion

		#region Static Methods
		/// <summary>
		/// Obtains a reference to a client-side script function that causes, when invoked,
		/// the control to raise a CallBack event to the server. This method also passes
		/// a parameter to the server control that performs the post-back processing on
		/// the server.
		/// </summary>
		/// <example>
		/// // Replaces the submit function of the button with the CallBack invoking function.
		/// btnSend.Attributes.Add ("onclick", CallBackHelper.GetCallbackEventReference(btnSend) + " return false;");
		/// </example>
		/// <param name="control"></param>
		/// <param name="argument"></param>
		/// <returns></returns>
		public static string GetCallbackEventReference(Control control, string argument)
		{
			if (control == null)
				throw new ArgumentNullException("control");
			
			return String.Format("{0}('{1}','{2}');", CallBackClientFunction, control.UniqueID, argument);
		}

		/// <summary>
		/// Obtains a reference to a client-side script function that causes, when invoked,
		/// the control to raise a CallBack event to the server.
		/// </summary>
		/// <example>
		/// // Replaces the submit function of the button with the CallBack invoking function.
		/// btnSend.Attributes.Add ("onclick", CallBackHelper.GetCallbackEventReference(btnSend) + " return false;");
		/// </example>
		/// <param name="control"></param>
		/// <returns></returns>
		public static string GetCallbackEventReference(Control control)
		{
			return GetCallbackEventReference(control, "");
		}

		/// <summary>
		/// Appends javascript: to the beginning of the return from a
		/// GetCallbackEventReference call to allow hyperlink CallBack processing on the
		/// server.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="argument"></param>
		/// <returns></returns>
		public static string GetCallbackClientHyperlink(Control control, string argument)
		{
			return String.Format("javascript:{0}", GetCallbackEventReference(control, argument));
		}

		/// <summary>
		/// Enables AJAX on a Page.
		/// </summary>
		/// <remarks>
		/// This method will automatically be called if the page contains any
		/// AjaxControl or if the SetCallBackTimerInterval method is called.
		/// 
		/// When AJAX is enabled on the page, the page will be stored in the session so that
		/// it can be retrieved by the AjaxHttpModule during a CallBack request by the client.
		/// 
		/// The Load event of the page and its child controls is not raised during a CallBack.
		/// If you want to handle the CallBack event instead, implement the ICallBackEventHandler interface
		/// on the page.
		/// 
		/// The default path for the script file "CallBackObject.js" is "/ajax/script".
		/// If you want to change it put
		/// 
		///		<add key="CallBackScriptPath" value="ajaxscriptpath" />
		///	
		///	in the appSettings section of the web.config file.
		/// </remarks>
		public static void EnableAjaxOnPage()
		{
			if ( IsCallBack ) return;

			Page page = (Page) HttpContext.Current.Handler;

			if (!page.IsClientScriptBlockRegistered( "CALLBACK_FOR_AJAX" )) 
			{            
				// Provides the location of the script file.
				string location = ConfigurationSettings.AppSettings["CallBackScriptPath"];

				if (location == null)
					location = "/ajax/script";  // use the default location

				// Create client script block.
				string includeScript = String.Format("<script language=\"javascript\" src=\"{0}/{1}\"></script>", location, "CallBackObject.js");
				page.RegisterClientScriptBlock( "CALLBACK_FOR_AJAX", includeScript );

				SessionPage = page;
			}
		}

		/// <summary>
		/// Registers the javascript that performs a CallBackStartup when the browser
		/// returns to an AJAX enabled page by the Back button.
		/// </summary>
		/// <remarks>
		/// Users except to return to the same page that they were viewing when they press
		/// the Back button of the browser. The browser loads the previous html so any
		/// page processing that was made by AJAX enabled pages is lost. In order to overcome
		/// this obstacle, RenderedByScriptControl controls invoke RegisterCallBackStartupScript
		/// that puts a script on the page that invokes a special CallBack
		/// (a CallBackStartup) when the Back button of the browser brings back an
		/// AJAX enabled page.
		/// 
		/// RenderedByScriptControl controls should check for a CallBackStartup at their
		/// RenderByScript method and act accordingly, (i.e. the AjaxPanel renders by
		/// script all of its controls on the page)
		/// </remarks>
		public static void RegisterCallBackStartupScript()
		{
			if ( IsCallBack ) return;

			string STARTUP_SCRIPT_FORMAT = @"
			<script language='javascript'>
				var ajaxcallback_prevFunc=null;

				function ajaxcallback__STATECHANGED()
				{{
					if (document.readyState=='complete')
						ajaxcallback__INIT();

					if (ajaxcallback_prevFunc != null)
						ajaxcallback_prevFunc();
				}}

				function ajaxcallback__INIT()
				{{
					var doStartUp = document.all.{0};
					if (doStartUp != null)
					{{
						if (doStartUp.value == 'true')
							AJAXCbo.DoCallBackStartup();
						else
							doStartUp.value = 'true';
					}}
				}}

				if ('onreadystatechange' in document)
				{{
					ajaxcallback_prevFunc=document.onreadystatechange;
					document.onreadystatechange=ajaxcallback__STATECHANGED;
				}}
				else
					ajaxcallback__INIT();
			</script>";

			System.Web.UI.Page page = (System.Web.UI.Page)HttpContext.Current.Handler;

			// Firefox, when performing a refresh, loads the page but keeps any INPUT
			// field values. Thus, it invokes a CallBackStartup. To stop this, every
			// time the page is loaded, the name of the DOSTARTUP INPUT field is different.
			string doStartupName = "DOSTARTUP_" + DateTime.Now.Ticks;

			if (!page.IsStartupScriptRegistered("CALLBACKSTARTUP_SCRIPT"))
				page.RegisterStartupScript ("CALLBACKSTARTUP_SCRIPT", String.Format(STARTUP_SCRIPT_FORMAT, doStartupName));

			// It simply checks if the hidden field is inserted in the page. If
			// RegisterHiddenField is called during a PreRender event AND during
			// a Render, the field will be written in the page twice.
			if (!page.IsStartupScriptRegistered("AJAXCALLBACK_DOSTARTUP"))
			{
				page.RegisterStartupScript ("AJAXCALLBACK_DOSTARTUP", "");
				page.RegisterHiddenField (doStartupName, "");
			}
		}

		/// <summary>
		/// Defines the time between repeated automatic callbacks of the page.
		/// </summary>
		/// <param name="milliSeconds">Set it to zero in order to disable CallBackTimer</param>
		public static void SetCallBackTimerInterval(int milliSeconds)
		{
			if (milliSeconds > 0)
			{
				if ( IsCallBack )
					Write (String.Format("AJAXCbo.SetIntervalForCallBack({0});", milliSeconds));
				else
				{
					EnableAjaxOnPage();
					Page page = (Page) HttpContext.Current.Handler;
					page.RegisterStartupScript ("AJAX_CALLBACKTIMER_SCRIPT", String.Format("<script language=\"javascript\">AJAXCbo.SetIntervalForCallBack({0});</script>", milliSeconds));
				}
			}
			else
			{
				if ( IsCallBack )
					Write ("AJAXCbo.ClearIntervalForCallBack();");
				else
					throw new Exception("CallBackTimer can be cleared only during a CallBack.");
			}
		}
		#endregion

		#region Static Methods for javascript writing
		/// <summary>
		/// Produces the javascript that redirects to a url.
		/// </summary>
		/// <param name="url"></param>
		public static void Redirect(string url)
		{
			Response.Clear();

			url = url.Trim();
			if (url[0] == '~')
			{
				string appPath = Request.ApplicationPath;
				if (appPath == "/")
					appPath = String.Empty;

				url = url.Remove(0, 1).Insert(0, appPath);
			}

			Write(String.Format("window.open(\"{0}\", \"_self\");\r\n", url));
			End();
		}

		/// <summary>
		/// Produces the javascript that will set the attributes of a control.
		/// </summary>
		/// <remarks>
		/// The attributes must be of this format:
		/// "attrib1=value1|attrib2=value2|attrib3=value3"
		/// </remarks>
		/// <param name="clientID">ClientID of the control</param>
		/// <param name="attributes">Formatted list of attributes</param>
		public static void WriteSetAttributesOfControl(string clientID, string attributes)
		{
			Write( String.Format("AJAXCbo.SetAttributesOfControl(\"{0}\",\"{1}\");\r\n", clientID, attributes) );
		}

		/// <summary>
		/// Produces the javascript that will a new element on the page.
		/// </summary>
		/// <param name="parentID">The id of the element that will contain the new element</param>
		/// <param name="elementID">The id of the new element</param>
		/// <param name="html">The innerHTML of the new element</param>
		/// <param name="beforeElemID">The id of the element that the new element must be inserted before it. Use null to append the new element at the end of the parent element</param>
		public static void WriteAddElementScript(string parentID, string tagName, string elementID, string html, string beforeElemID)
		{
			string before = (beforeElemID != null) ? String.Format("\"{0}\"", beforeElemID) : "null";
			Write( String.Format("AJAXCbo.AddElementScript(\"{0}\",\"{1}\",\"{2}\",{3},{4});\r\n", parentID, tagName, elementID, EncodeString(html), before) );
		}

		/// <summary>
		/// Provides the javascript that will remove an existing element from the page.
		/// </summary>
		/// <param name="parentID">The id of the element that contains the element to be removed</param>
		/// <param name="elementID">The id of the element to be removed</param>
		public static void WriteRemoveElementScript(string parentID, string elementID)
		{
			Write( String.Format("AJAXCbo.RemoveElementScript(\"{0}\",\"{1}\");\r\n", parentID, elementID) );
		}

		/// <summary>
		/// Provides the javascript that will set the value of a field on the page.
		/// </summary>
		/// <remarks>
		/// Use this if you want to manipulate, during CallBack, a hidden field previously
		/// registered by the Page.RegisterHiddenField method.
		/// </remarks>
		/// <param name="fieldName"></param>
		/// <param name="fieldValue"></param>
		public static void WriteSetFieldScript(string fieldName, string fieldValue)
		{
			Write( String.Format("AJAXCbo.SetFieldScript({0},\"{1}\");\r\n", EncodeString(fieldValue), fieldName) );
		}

		/// <summary>
		/// Provides the javascript that will se the innerHTML of an element of the page.
		/// </summary>
		/// <param name="html"></param>
		/// <param name="elementID">The id of the element of the page</param>
		public static void WriteSetHtmlOfElementScript(string html, string elementID)
		{
			Write( String.Format("AJAXCbo.SetHtmlOfElementScript({0},\"{1}\");\r\n", EncodeString(html), elementID) );
		}

		public static void WriteSetHtmlOfPageScript(string html)
		{
			Write ( String.Format("AJAXCbo.SetHtmlOfPage({0});\r\n", EncodeString(html)) );
		}

		public static void WriteSetVisibilityOfElementScript(string elementID, bool visible)
		{
			Write ( String.Format("AJAXCbo.SetVisibilityOfElement(\"{0}\",{1});\r\n", elementID ,visible.ToString().ToLower()) );
		}

		/// <summary>
		/// Provides the javascript that will invoke an alert message box.
		/// </summary>
		/// <param name="message"></param>
		public static void WriteAlert(string message)
		{
			Write ( String.Format("AJAXCbo.Alert({0});\r\n", EncodeString(message)) );
		}

		/// <summary>
		/// It appends a "'AJAX_LOADING_OK';" string to the end, so that the client
		/// knows that the loading of the CallBack javascript data wasn't aborted,
		/// but they were fully loaded.
		/// </summary>
		/// <remarks>
		/// Called by the End method.
		/// </remarks>
		internal static void WriteEndSignature()
		{
			Write ("'AJAX_LOADING_OK';");
		}

		/// <summary>
		/// Converts a string to a javascript string.
		/// </summary>
		/// <example>
		/// CallBackHelper.Write (String.Format("alert({0});", CallBackHelper.EncodeString("Alert invoked by javascript.")));
		/// </example>
		/// <param name="str"></param>
		/// <returns></returns>
		public static string EncodeString(string str)
		{
			System.Text.StringBuilder sb = new System.Text.StringBuilder(str);
			sb.Replace("\\", "\\\\");
			sb.Replace("\"", "\\\"");
			sb.Replace("\r", "\\r");
			sb.Replace("\n", "\\n");
			sb.Replace("\t", "\\t");
			sb.Insert(0, '\"');
			sb.Append('\"');
			return sb.ToString();
		}

		/// <summary>
		/// Writes to the Response. Included for convenience.
		/// </summary>
		/// <remarks>
		/// Use this method if you want to send custom javascript code for the client to execute.
		/// Use EncodeString if you want to append a string for your javascript code.
		/// </remarks>
		/// <example>
		/// CallBackHelper.Write (String.Format("var span = document.getElementById('{0}');", label.ClientID));
		/// CallBackHelper.Write (String.Format("span.innerHTML = {0});", CallBackHelper.EncodeString("Changed by javascript")));
		/// </example>
		/// <param name="text"></param>
		public static void Write( string text)
		{
			Response.Write (text + "\r\n");
		}

		/// <summary>
		/// Use this method instead of Response.End during a CallBack.
		/// </summary>
		/// <remarks>
		/// Writes the End signature, ends the writing to the Response and causes
		/// CompleteRequest on the application.
		/// </remarks>
		public static void End()
		{
			WriteEndSignature();

			HttpResponse hr = CallBackHelper.Response;
	    
			hr.StatusCode = 200;
			hr.StatusDescription = "OK";

			hr.Flush();

			AjaxHttpModule.CompletedCallBack = true;
			hr.End();
		}
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License

About the Author

Argiris Kirtzidis
Web Developer
Greece Greece
No Biography provided

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 28 May 2007
Article Copyright 2005 by Argiris Kirtzidis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid