Google

Saturday, November 17, 2007

How to access a client-side control in asp.net code behind file

Accessing client-side variables/elements on the server side is not a straightforward affair. This is because the elements you create using javascript are not "server" controls, so you cannot directly access them in your code behind code like regular asp.net server controls (by the way, server controls are controls that have the runat="server" attribute set.) To achieve this functionality, we use hidden controls. Hidden controls are HTML controls that remain "hidden" on the page. In other words, you can assign a text value to the hidden controls (just like label, textbox etc.), but their contents are not rendered on the screen. By creating hidden controls with runat="server" set, we can access them both on client-side and server-side code. Let us take an example. Suppose we have a simple .aspx page which has three elements : 1. An Asp.Net ListBox control, 2. A button for adding new options to the listbox, and 3. A button for posting back the page. Here's what it looks like :

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!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 runat="server">
    <title>Untitled Page</title>
    <script language="javascript" type="text/javascript">
        function myMethod()
        {
            var listbox = document.getElementById('ListBox1');
            var newElement = document.createElement('option');
            newElement.text = 'Test';
            listbox.options.add(newElement);
            window.event.returnValue = false;
        }       
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <input id="Submit1" onclick="myMethod();" type="submit"
                value="Add Element" />
            <asp:ListBox ID="ListBox1" runat="server"></asp:ListBox>
            <input id="Submit2" type="submit" value="PostBack Page" />
        </div>
    </form>
</body>
</html>
Run the above page. Observe that on clicking on the first button, our javascript method "myMethod()" successfully adds new elements to the listbox. However, as soon as you postback the page using the second button, the elements that you added are lost. Why ? The reason for this is that although we have added the controls on the client-side, the viewstate variable on our page hasn't changed at all. It still says that the page has only one server control - the Listbox. So while processing the page upon postback, when asp.net constructs the "tree" of all controls on the page, it does not realize that there have been a few listbox elements added to the page on the client side (because the viewstate doesn't say so). Hence, when it renders back the page upon postback, it just renders an empty listbox. To get around this, we would have to make an "entry" for the new elements in the viewstate, which is not possible because viewstate is encrypted. The second option is to use a hidden variable with runat="server", and put a comma seperated list of the new listbox elements added in this hidden variable. That way, when the page posts back, we read the value in the hidden variable and accordingly add new elements to the Listbox. Here's the modified .Aspx page for this :
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!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 runat="server">
    <title>Untitled Page</title>
    <script language="javascript" type="text/javascript">
        function myMethod()
        {
            var listbox = document.getElementById('ListBox1');
            var newElement = document.createElement('option');
            newElement.text = 'Test';
            listbox.options.add(newElement);
            document.getElementById('hdnListElements').value = document.getElementById('hdnListElements').value + ',' + newElement.text;
            window.event.returnValue = false;
        }         
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <input id="Submit1" onclick="myMethod();" type="submit"
                value="Add Element" />
            <asp:ListBox ID="ListBox1" runat="server"></asp:ListBox>
            <input id="Submit2" type="submit" value="PostBack Page" />
            <input type="hidden" runat="server" id="hdnListElements" />
        </div>
    </form>
</body>
</html>
Observe carefully the highlighted line. We are basically creating a comma-seperated list of all the elements added to the listbox on the clientside. On the server-side, we read these values, and populate the listbox with the newly added child elements. Here's the C# code :
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
            string str = hdnListElements.Value;
            // If the hidden variable is empty, no new elements added.
            if (!String.IsNullOrEmpty(str))
            {
                // Split the comma-seperated list into an array of strings.
                string[] strArray = str.Split(",".ToCharArray(),StringSplitOptions.RemoveEmptyEntries);
                foreach (string sTemp in strArray)
                {
                    // foreach newly added element, add a ListItem to the listbox control
                    ListBox1.Items.Add(new ListItem(sTemp, sTemp));
                }
                // Clear the hidden variable, so it does not contain the currently added elements.
                hdnListElements.Value = String.Empty;
            }
    }
}
And that is it. That's a pure and simple way to access client-side variables / controls in server-side code.

No comments: