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.

Yossi Shmueli

Keeping it green since 1995

comments powered by Disqus