The ability to have clean, predictable, ID attributes on
rendered HTML elements is something developers have long asked for with Web
Forms (ID values like “ctl00_ContentPlaceholder1_ListView1_ctrl0_Label1” are
not very popular). Having control over the ID values rendered helps make
it much easier to write client-side JavaScript against the output, makes it
easier to style elements using CSS, and on large pages can help reduce the
overall size of the markup generated.
New ClientIDMode Property on Controls
ASP.NET 4 supports a new ClientIDMode property on the
Control base class. The ClientIDMode property indicates how controls
should generate client ID values when they render. The ClientIDMode
property supports four possible values:
AutoID—Renders the output as in .NET 3.5 (auto-generated IDs
which will still render prefixes like ctrl00 for compatibility)
Predictable (Default)— Trims any “ctl00” ID string and if a
list/container control concatenates child ids (example: id=”ParentControl_ChildControl”)
Static—Hands over full ID naming control to the developer –
whatever they set as the ID of the control is what is rendered (example:
id=”JustMyId”)
Inherit—Tells the control to defer to the naming behavior
mode of the parent container control
The ClientIDMode property can be set directly on individual
controls (or within container controls – in which case the controls within them
will by default inherit the setting):
Or it can be specified at a page or usercontrol level (using
the <%@ Page %> or <%@ Control %> directives) – in which case
controls within the pages/usercontrols inherit the setting (and can optionally
override it):
Or it can be set within the web.config file of an
application – in which case pages within the application inherit the setting
(and can optionally override it):
This gives you the flexibility to customize/override the
naming behavior however you want.
Example: Using the ClientIDMode property to control the IDs
of Non-List Controls
Let’s take a look at how we can use the new ClientIDMode
property to control the rendering of “ID” elements within a page. To help
illustrate this we can create a simple page called “SingleControlExample.aspx”
that is based on a master-page called “Site.Master”, and which has a single
<asp:label> control with an ID of “Message” that is contained with an
<asp:content> container control called “MainContent”:
Within our code-behind we’ll then add some simple code like
below to dynamically populate the Label’s Text property at runtime:
If we were running this application using ASP.NET 3.5 (or
had our ASP.NET 4 application configured to run using 3.5 rendering or
ClientIDMode=AutoID), then the generated markup sent down to the client would
look like below:
This ID is unique (which is good) – but rather ugly because
of the “ct100” prefix (which is bad).
Markup Rendering when using ASP.NET 4 and the ClientIDMode
is set to “Predictable”
With ASP.NET 4, server controls by default now render their
ID’s using ClientIDMode=”Predictable”. This helps ensure that ID values
are still unique and don’t conflict on a page, but at the same time it makes
the IDs less verbose and more predictable. This means that the generated
markup of our <asp:label> control above will by default now look like
below with ASP.NET 4:
Notice that the “ct100” prefix is gone. Because the
“Message” control is embedded within a “MainContent” container control, by
default it’s ID will be prefixed “MainContent_Message” to avoid potential
collisions with other controls elsewhere within the page.
Markup Rendering when using ASP.NET 4 and the
ClientIDMode is set to "Static"
Sometimes you don’t want your ID values to be nested
hierarchically, though, and instead just want the ID rendered to be whatever
value you set it as. To enable this you can now use ClientIDMode=static, in
which case the ID rendered will be exactly the same as what you set it on the
server-side on your control. This will cause the below markup to be
rendered with ASP.NET 4:
This option now gives you the ability to completely control
the client ID values sent down by controls.
Example: Using the ClientIDMode property to control the IDs
of Data-Bound List Controls
Data-bound list/grid controls have historically been the
hardest to use/style when it comes to working with Web Form’s automatically
generated IDs. Let’s now take a look at a scenario where we’ll customize
the ID’s rendered using a ListView control with ASP.NET 4.
The code snippet below is an example of a ListView control
that displays the contents of a data-bound collection — in this case, airports:
We can then write code like below within our code-behind to
dynamically databind a list of airports to the ListView above:
At runtime this will then by default generate a <ul>
list of airports like below. Note that because the <ul> and
<li> elements in the ListView’s template are not server controls, no IDs
are rendered in our markup:
Adding Client ID’s to Each Row Item
Now, let's say that we wanted to add client-ID's to the
output so that we can programmatically access each <li> via
JavaScript. We want these ID’s to be unique, predictable, and
identifiable.
A first approach would be to mark each <li> element
within the template as being a server control (by giving it a runat=server
attribute) and by giving each one an id of "airport":
By default ASP.NET 4 will now render clean IDs like below
(no ctl001-like ids are rendered):
Using the ClientIDRowSuffix Property
Our template above now generates unique ID’s for each
<li> element – but if we are going to access them programmatically on the
client using JavaScript we might want to instead have the ID’s contain the
airport code within them to make them easier to reference. The good news
is that we can easily do this by taking advantage of the new ClientIDRowSuffix
property on databound controls in ASP.NET 4 to better control the ID’s of our
individual row elements.
To do this, we’ll set the ClientIDRowSuffix property to
“Code” on our ListView control. This tells the ListView to use the
databound “Code” property from our Airport class when generating the ID:
And now instead of having row suffixes like “1”, “2”, and
“3”, we’ll instead have the Airport.Code value embedded within the IDs (e.g:
_CLE, _CAK, _PDX, etc):
You can use this ClientIDRowSuffix approach with other
databound controls like the GridView as well. It is useful anytime you want to
program row elements on the client – and use clean/identified IDs to easily
reference them from JavaScript code.