Friday, April 24, 2009

ClientID feature of ASP.NET 4.0

One of the new features being added to ASP.NET 4.0 is the ability to control the client side IDs that are generated by the framework. Previously the framework use to generate unique ClientID's for the controls. These ClientID's were generated by combining "ctl00" with the parent container's name like "ctl00_ContainerDIV_ctl01_Textbox1".


The Problem
In the earlier versions of .NET framework, the ClientID's were generated uniquely by the framework. It was much frustratingto use these ClientID's in the JavaScript of asp.net web page. If by some mean the develop hard codes the ClientID in the JavaScript and another developer changes the Controls ID, then the JavaScript use to throw error, since it does not recognize the old ClientID which was hard coded. To avoid such scenarios, developers started using server tags for Control.ClientID in JavaScript as shown in the below section.


Old Solution
Each control has a property called ClientID that is a read only and supplies the unique client side ID. This can be used in code behind for dynamically adding client side ID's to scripts. One such example is shown below:

<script type="text/javascript">
function ShowMessage(){
alert('<%= Control.ClientID %>');
}
</script>

ASP.NET 4.0 Solution
There is not really a clean way to use the ClientID property with lots of controls and lots of external script files. With the increase in use of client side scripting and ajax, it became important to make the ClientID property writable. The solution to this problem was found by introducing ClientIDMode property to each control. Depending on various modes the developer will have full control over the client side Id's of a control.

Client ID Modes
There is now a new property on every control (this includes pages and master pages as they inherit from control) called ClientIDMode that is used to select the behavior of the client side ID.

<asp:Label ID="Label1" runat="server" ClientIDMode="[Mode Type]" />

Mode Types
Legacy: The default value if ClientIDMode is not set anywhere in the control hierarchy. This causes client side IDs to behave the way they did in version 2.0,3.0 and 3.5 of the framework. This mode will generate an ID similar to "ctl00_ContainerDIV_ctl01_Textbox1."

markup:

<asp :TextBox ID ="txtEcho" runat ="server" Width ="65%" ClientIDMode ="Legacy" />

output:

<input id="ctl00_MasterPageBody_ctl00_txtEcho" style="width: 65%"
name="ctl00$MasterPageBody$ctl00$txtEcho" />

Inherit: This is the default behavior for every control. This looks to the controls parent to get its value for ClientIDMode. You do not need to set this on every control as it is the default, this is used only when the ClientIDMode has been changed and the new desired behavior is to inherit from the controls parent.

Static: This mode does exactly what you think it would, it makes the client side ID static. Meaning that what you put for the ID is what will be used for the client side ID.
[Warning, this means that if a static ClientIDMode is used in a repeating control the developer is responsible for ensuring client side ID uniqueness.]

markup:

<asp:TextBox ID="txtEcho2" runat="server" Width="65%" ClientIDMode="Static" />

output:

<input id="txtEcho2" style="width: 65%" name="ctl00$MasterPageBody$ctl00$txtEcho2" />

Predictable: This mode is used when the framework needs to ensure uniqueness but it needs to be done so in a predictable way.The most common use for this mode is on databound controls. The framework will traverse the control hierarchy prefixing the supplied ID with it’s parent control ID until it reaches a control in the hierarchy whose ClientIDMode is defined as static. In the event that the control is placed inside a databound control a suffix with a value that identifies that instance will also be added to the supplied ID. The ClientIDRowSuffix property is used to control the value that will be used as a suffix. This mode will generate an ID similar to "Gridview1_Label1_0".

1. With no ClientIDRowSuffix defined, this is also the behavior for databound controls without a datakeys collection e.g. Repeater Control. Notice that the framework has traversed the control hierarchy and prefixed the ID with the parent’s ID and suffixed the ID with row index.

markup:

<asp:GridView ID="EmployeesNoSuffix" runat="server" AutoGenerateColumns="false"
ClientIDMode="Predictable" >
<Columns>
<asp:TemplateField HeaderText="ID">
<ItemTemplate>
<asp:Label ID="EmployeeID" runat="server" Text='<%# Eval("ID") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:Label ID="EmployeeName" runat="server" Text='<%# Eval("Name") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

output:

<table id="EmployeesNoSuffix" style="border-collapse: collapse" cellspacing="0" rules="all" border="1">
<tbody>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
</tr>
<tr>
<td><span id="EmployeesNoSuffix_EmployeeID_0">1</span></td>
<td><span id="EmployeesNoSuffix_EmployeeName_0">EmployeeName1</span></td>
</tr>
...
<tr>
<td><span id="EmployeesNoSuffix_EmployeeID_8">9</span></td>
<td><span id="EmployeesNoSuffix_EmployeeName_8">EmployeeName9</span></td>
</tr>
</tbody>
</table>

2. With a ClientIDRowSuffix defined, this looks in the control’s datakeys collection for the value and then suffixes the ID with that value.

markup:

<asp:GridView ID="EmployeesSuffix" runat="server" AutoGenerateColumns="false"
ClientIDMode="Predictable" ClientIDRowSuffix="ID" >
<Columns>
<asp:TemplateField HeaderText="ID">
<ItemTemplate>
<asp:Label ID="EmployeeID" runat="server" Text='<%# Eval("ID") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:Label ID="EmployeeName" runat="server" Text='<%# Eval("Name") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

output:

<table id="EmployeesSuffix" style="border-collapse: collapse" cellspacing="0" rules="all" border="1">
<tbody>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
</tr>
<tr>
<td><span id="EmployeesSuffix_EmployeeID_1">1</span></td>
<td><span id="EmployeesSuffix_EmployeeName_1">EmployeeName1</span></td>
</tr>
...
<tr>
<td><span id="EmployeesSuffix_EmployeeID_9">9</span></td>
<td><span id="EmployeesSuffix_EmployeeName_9">EmployeeName9</span></td>
</tr>
</tbody>
</table>

3. With a ClientIDRowSuffix defined, but instead of just one value a compound value will be used. Exhibits the same behavior as one value but it will suffix both values onto the ID.

markup:

<asp:GridView ID="EmployeesCompSuffix" runat="server" AutoGenerateColumns="false"
ClientIDMode="Predictable" ClientIDRowSuffix="ID, Name" >
<Columns>
<asp:TemplateField HeaderText="ID">
<ItemTemplate>
<asp:Label ID="EmployeeID" runat="server" Text='<%# Eval("ID") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:Label ID="EmployeeName" runat="server" Text='<%# Eval("Name") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

output:

<table id="EmployeesCompSuffix" style="border-collapse: collapse" cellspacing="0" rules="all" border="1">
<tbody>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
</tr>
<tr>
<td><span id="EmployeesCompSuffix_EmployeeID_1_EmployeeName1">1</span></td>
<td><span id="EmployeesCompSuffix_EmployeeName_1_EmployeeName1">EmployeeName1</span></td>
</tr>
...
<tr>
<td><span id="EmployeesCompSuffix_EmployeeID_9_EmployeeName9">9</span></td>
<td><span id="EmployeesCompSuffix_EmployeeName_9_EmployeeName9">EmployeeName9</span></td>
</tr>
</tbody>
</table>

Thanks to Microsoft ASP.NET Team for adding this valuable feature!

0 comments:

Post a Comment