How to create a complete AJAX Server Control. Part 2.

Posted on Updated on

In this post I’m going to continue with the sample of the part 1.

Now it’s time to start adding functionality to the control.

First of all I’m going to add Items to the control.

To do that I have declared a class that contains the data that I wanted to show. I could have defined an interface and then implement it in a class out of the project, but for this presentation I’ve kept it simple.

ShoppingCartItem.cs

public class ShoppingCartItem
	{
		public DateTime DateAdded { get; set; }
		public string Text { get; set; }
		public string Description { get; set; }
		public int Quantity { get; set; }
		public float TotalPrice { get; set; }
	}

And now, I’ll define in the control class a collection property in where I’ll store all the items in the shopping cart.

I’ll call the property Items.

I’ve also added code to render some HTML for the items (<table><tr><td> style). And to show how to add client side functionality, I put it inside a non visible div that will be made visible in JS when we click on the cart.

The HTML elements are created in InitialiseControls(), CreateTableItemsHeader() and CreateHTMLItems() functions.

ShoppingCart.cs

	public class ShoppingCart : ScriptControlBase
	{
		List items = new List();

		/// 
		/// Div control used as a pop-up container to display the selected items
		/// 
		HtmlGenericControl itemsDiv;

		/// 
		/// Table where the items are rendered
		/// 
		HtmlTable tableItems;

		/// 
		/// Shopping Cart Items
		/// 
		public List Items{get{return items;}
			set
			{
				if (value == null) items = new List();
				else items = value;
			}
		}

		public ShoppingCart(): base(false, HtmlTextWriterTag.Div)
		{
		}

		#region Control Rendering

		protected override void OnPreRender(EventArgs e)
		{
			if (!this.DesignMode)
			{
				if (ScriptManager.GetCurrent(Page) == null)
				{
					throw new HttpException("ScriptManager control must.");
				}
				InitialiseControls();

				CreateHTMLItems();
			}

			base.OnPreRender(e);
		}

		private void InitialiseControls()
		{
			Image cartImage = new Image();
			cartImage.ID = "cartImage";
			cartImage.Attributes["class"] = "cartImage";
			cartImage.ToolTip = "Shopping Cart";
			cartImage.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(),"AjaxControl.Images.cart.png");
			this.Controls.Add(cartImage);

			itemsDiv = new HtmlGenericControl("div");
			itemsDiv.ID = "itemsDiv";
			itemsDiv.Attributes["class"] = "itemsDiv";
			itemsDiv.Style.Add(HtmlTextWriterStyle.Display, "none");
			this.Controls.Add(itemsDiv);

			tableItems = new HtmlTable();
			tableItems.Attributes["class"] = "itemsTable";
			itemsDiv.Controls.Add(tableItems);

		}

		/// 
		/// Creates the items to be rendered
		/// 
		public void CreateHTMLItems()
		{
			tableItems.Rows.Clear();

			CreateTableItemsHeader();

			// Add data rows
			foreach (var item in items.OrderBy(i => i.DateAdded))
			{
				HtmlTableRow rowItem = new HtmlTableRow();
				rowItem.Attributes["class"] = "itemRow";
				tableItems.Rows.Add(rowItem);

				HtmlTableCell cellText = new HtmlTableCell();
				//...
				rowItem.Cells.Add(cellText);
				//...
			}
		}

		/// 
		/// Creates a heading to close the table
		/// 
		private void CreateTableItemsHeader()
		{
			//...

			Image closeImage = new Image();
			closeImage.ID = "closeItemsImage";
			closeImage.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "AjaxControl.Images.cancel.png");
			//...
			cellHead.Controls.Add(closeImage);
		}

		#endregion

	}

Once we have the server side of the control ready we can start with the client side.

In the JS class I have added some event handling. I first get the html elements that represent the cart (to add a onclick event), then the items div (to make the items visible) and finally the close image to hide the items again.

The method _addHandlers() will hook up all the events and the method _clearHandlers() will remove them.

Important: Something to notice is that in JS we don’t have the concept of delegates and if we add a handler using the standard method, then inside the method we won’t have access to the current object, this. In the MS AJAX Framework, they have implemented the concept using Function.createDelegate(this, this._cartImageClick), in there the firs parameter is the instance of the object that we want to access as this inside the event handler and the second is the handler. Now we can have access to all the methods and members of the class inside the handler.

ShoppingCart.js

var $ShoppingCart = AjaxControl.ShoppingCart = function(element)
{
	this._element = element; // div control that contains everything

	AjaxControl.ShoppingCart.initializeBase(this, [element]);

	this._cartImage = $get(element.id + "_cartImage");
	this._itemsDiv = $get(element.id + "_itemsDiv");
	this._closeItemsImage = $get(element.id + "_closeItemsImage"); 

}

// ------------------- Control Initialisation and Destruction ------------------------
$ShoppingCart.prototype.initialize = function()
{
	$ShoppingCart.callBaseMethod(this, "initialize");

	this._addHandlers();
}

// As the control implements Sys.IDisposable, the MS Ajax Framework requires of this method.
// This method will be use release used resources (specially required to work with Update Panels)
$ShoppingCart.prototype.dispose = function()
{
	$ShoppingCart.callBaseMethod(this, 'dispose');
}

$ShoppingCart.prototype._addHandlers = function()
{
	$addHandlers(this._cartImage, {
		click: Function.createDelegate(this, this._cartImageClick)
	});
	$addHandlers(this._closeItemsImage, {
		click: Function.createDelegate(this, this._closeItemsImageClick)
	});
}

$ShoppingCart.prototype._clearHandlers = function()
{
	// remove event handlers to avoid memory leaks
	$clearHandlers(this._cartImage);
	$clearHandlers(this._closeItemsImage);

}

// -------------------- HTML Events ---------------------

$ShoppingCart.prototype._cartImageClick = function(e)
{
	this._itemsDiv.style.display = "block";
}

$ShoppingCart.prototype._closeItemsImageClick = function(e)
{
	this._itemsDiv.style.display = "none";
}

In the web page I have added some items to the shopping cart so we can test the functionality.

ShoppingCart.aspx.cs

	public partial class ShoppingCart : System.Web.UI.Page
	{
		protected void Page_Load(object sender, EventArgs e)
		{
			if(! IsPostBack)
			{
				var items = new List
				{
					new ShoppingCartItem{DateAdded = DateTime.Now.AddMinutes(-20),Text = "Learn Ajax in 1h!",
										Description = "If you want to learn Ajax in 1h, this is your book.",
										Quantity = 1,TotalPrice = 28.90f},
					new ShoppingCartItem{DateAdded = DateTime.Now.AddMinutes(-20),Text = "Ajax for Dummies!",
										Description = "If you think that you are hopeless, this is your book.",
										Quantity = 2,TotalPrice = 70.00f},
					new ShoppingCartItem{DateAdded = DateTime.Now.AddMinutes(-20),Text = "Advanced Ajax Server Controls",
										Description = "When you want to go further, this is your book.",
										Quantity = 1,TotalPrice = 86.50f},

				};

				Cart1.Items = items;
			}
		}
	}

Now you can run the example and click on the cart and close image so you can see how we have a server control that handles all the data in the server side and still can run some client functionality without doing any post back.

You can download the code here.

Important: I couldn’t upload the file as it was a zip file, so I added the extension jpg. After saving the file, remove the extension and unzip it normally.

One thought on “How to create a complete AJAX Server Control. Part 2.

    Phil said:
    February 8, 2013 at 20:11

    cannot download ajaxservercontrol-part1-6-zip.jpg

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s