Updating an UpdatePanel in the Client side

In the last couple of weeks I have been learning the ASP.Net Ajax extensions and Ajax Control Toolkit. It really is an amazing framework for simple and complex web applications.

While I was practicing the technology, I notice that there was something missing. I couldn't update an UpdatePanel from a JavaScript in the client side.

Why this is useful? Well, I'll give you an example:
Suppose we have a web site which has multiple update panel which are needed to be updated every 5 seconds (If an update has occurred in the data they display). The simple way to do this is to add a timer control from the extensions, and add a tick event every 5 seconds.
What's the problem with that? My team leader, Doron, found this article in msdn:
http://msdn.microsoft.com/msdnmag/issues/07/06/WickedCode/Default.aspx?loc=en

The article mainly deals with performance issues in the ASP.Net Ajax extensions. One of them refers to performance of the UpdatePanel. When you are using an update panel in a web page, the whole request is posted back to the server when you want to update an update panel. That means that for each tick of the timer a regular request will be posted back to the server (I remind you, every 5 seconds). Now If you have even two or three GridView control, that could be very inefficient. So the solution is to create a javascript timer which every 5 seconds calls a WebMethod from a web service, which checks if the data has been updated, and then the client needs to trigger a post back of the particular update panel, which contains that data.

How to I trigger an update in an UpdatePanel in the client side?

At first I thought to create my own UpdatePanel which inherits from the original. But that could be problematic, especially with existing web forms.
I would need to replace all the panel with my own, not to mention problems with embedded resource in the original assembly that contains the UpdatePanel control.

I decided to create an extender for the update panel which adds an update() method to it's panel. Here's an example of how it should be used:

<script language=”javascript” type=”text/javascript”>
	function Button1_onclick() {
		var u = $get('<%= UpdatePanel1.ClientID %>');

		u.update();
	}
</script>
<asp:UpdatePanel ID=”UpdatePanel1″ runat=”server”>
	<ContentTemplate>
		<asp:TextBox ID=”TextBox1″ runat=”server”></asp:TextBox>
	</ContentTemplate>
</asp:UpdatePanel>

<ysa:UpdatePanelExtender ID=”UpdatePanelExtender1″ runat=”server”
	OnUpdated=”UpdatePanelExtender1_Updated” TargetControlID=”UpdatePanel1″>
</ysa:UpdatePanelExtender>

<input id=”Button1″ type=”button” value=”Client Button” onclick=”return Button1_onclick()” />

I created the extender using the extensibility infrastructure of the Ajax Control Toolkit. An extender contains three parts:

  • Class which inherits from ExtenderControlBase, which contains the server side code.
  • Behavior: a JavaScript object which contains the client side code.
  • Designer: optional. contains a definition of a designer for the extender.

To learn how to create an extender click here

In the UpdatePanelExtender (catchy name), I simply added a hidden button to the update panel:

protected override void CreateChildControls()
{
	// Adding the button that will be used to trigger the update :
	Button updateButton = CreateUpdateButton();

	TargetUpdatePanel.ContentTemplateContainer.Controls.Add(updateButton);

	// In case the target panel defines that the child controls can not trigger a postback, add the update button click event
	// to the triggers collection :
	if (!TargetUpdatePanel.ChildrenAsTriggers)
	{
		AddUpdateButtonAsTrigger(updateButton);
	}

	UpdateButton = updateButton;

	base.CreateChildControls();
}

private Button CreateUpdateButton()
{
	Button updateButton = new Button();
	updateButton.Style["display"] = “none“;
	updateButton.Text = ClientID + “_UpdateButton“;
	updateButton.Click += new EventHandler(UpdateButton_Click);
	updateButton.ID = ClientID + “_UpdateButton“;

	return updateButton;
}

private void AddUpdateButtonAsTrigger(Button updateButton)
{
	AsyncPostBackTrigger t = new AsyncPostBackTrigger();
	t.ControlID = updateButton.ClientID;
	t.EventName = “Click“;
	TargetUpdatePanel.Triggers.Add(t);
}

The update method simply calls the click() method in the button control:

initialize : function() {
	YsA.Web.UI.WebControls.UpdatePanelBehavior.callBaseMethod(this, ‘initialize‘);

	// Adding the update method to the update panel :
	var e = this.get_element();
	e.update = Function.createDelegate(this,this.update);
}

The update method simply calls the “click” method in the button control:

update : function() {
	var updateButton = $get(this._updateButtonClientID);
	updateButton.click();
}

_updateButtonClientID is a property that is initialized by the extender which contains the ID of the update button.

That's about it.

A solution which contains the source code and an example web form is attached to this post.

Known issues

I tried to create an event in the extender which will be triggered after the panel updates. I couldn't make it work. The final revision is in the source code, check it out. Maybe you could tell me what I did wrong.

I will be glad to read your comments, bugs you found, and improvement suggestions.

Have a great week.

Update

I've updated the extender. The updated version is in the UpdatePanelExtender Upgrade post. I've also removed the old version from this post.