Introduction
With the advent of ASP.NET about five years ago Microsoft created several
built-in Web Forms controls and among them are the
RadioButtonList and CheckboxList. These two controls have a pretty robust
and intuitive class structure but are lacking in a quite pratical aspect:
the ability to hide their individual ListItems!
Background
I must admit that hiding individual ListItems in a
RadioButtonList or CheckBoxList is not something that developers
have to do on a regular basis. However, when are
you required to hide them for pratical reasons it can become quite
frustrating. In one such case I needed to have a default
value for a RadioButtonList that I didn't want the user to see
but that I could reference programmatically using the
SelectedItem property. After trying several other approaches and
searching the web for other solutions it became abundantly clear to me that
I would have to create my own solution. The result I believe is a nice
workaround that is flexible enough for developers to use in their
existing applications without having to make a reference to an external
.dll file or web control library.
My Initial approach to Hiding ListItems... which didn't work
My initial approach to tackling this problem was
to reference a ListItem object in the RadioButtonList or CheckBoxList
control's Items collection and add a style attribute that would set its
display style to "none". Now a reasonable person would think
that this would work because it doesn't cause a compile or runtime
error. However, when the control is rendered as HTML to the
browser the attributes specified in the source code are
not rendered!!!
Here was my initial idea of hiding a ListItem which did
not work:
Public Shared Sub HideListItem(ByRef RbList As RadioButtonList)
RbList.Items(0).Attributes.Add("style", "display='none;'")
End Sub
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
HideListItem(Me.rbGender)
End Sub
When the page loads and you view the HTML source of the page this is what it
looks like:
<table id="rbGender" border="0" style="width:136px;">
<tr>
<td><input id="rbGender_0" type="radio" name="rbGender" value="-1" /><label for="rbGender_0">-1</label></td>
<td><input id="rbGender_1" type="radio" name="rbGender" value="0" /><label for="rbGender_1">Female</label></td>
<td><input id="rbGender_2" type="radio" name="rbGender" value="1" /><label for="rbGender_2">Male</label></td>
</tr>
</table>
You will notice that the attribute "style=display='none;'" is no where to be
found!
An appproach that works! Hiding the ListItem by using dynamically
generated DHTML
Becuase my style attribute was not being rendered as I specified in my
code. I decided to take another approach. By tapping into my knowledge of
DHTML I decided to dynamically generate some DHTML that would hide the ListItems
for me.
Check out the code below for additional details:
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
Dim jsCode As String = HideRadioButtonListItem(Me.rbGender)
Me.RegisterStartupScript("HideListItems", jsCode)
End Sub
Public Function HideRadioButtonListItem(ByRef RbList As RadioButtonList) As String
Dim IndexesHide() As String = {"0"}
Return HideRadioButtonListItems(RbList, IndexesHide)
End Function
Public Function HideRadioButtonListItems(ByRef RbList As RadioButtonList, ByVal IndexesToHide() As String) As String
Dim HideColumnOrRowBasedOnRepeatDirection As String = ""
If RbList.RepeatDirection = RepeatDirection.Horizontal Then
HideColumnOrRowBasedOnRepeatDirection = "td"
ElseIf RbList.RepeatDirection = RepeatDirection.Vertical Then
HideColumnOrRowBasedOnRepeatDirection = "tr"
End If
Dim CtrlClientID As String = RbList.ClientID
Dim JScriptCodeString As New System.Text.StringBuilder
JScriptCodeString.Append(" <script language=" + Chr(34) + "javascript" + Chr(34) + "> " & vbCrLf)
JScriptCodeString.Append(" var rbTable;" & vbCrLf)
JScriptCodeString.Append(" rbTable = document.getElementById(""" & CtrlClientID & """);" & vbCrLf)
JScriptCodeString.Append(" if ((rbTable == null) || (rbTable == undefined)) { } else { " & vbCrLf)
JScriptCodeString.Append(" var NestedLabels;" & vbCrLf)
JScriptCodeString.Append(" NestedLabels = rbTable.getElementsByTagName(""")
JScriptCodeString.Append(HideColumnOrRowBasedOnRepeatDirection & """);" & vbCrLf)
For i As Integer = 0 To IndexesToHide.Length - 1
JScriptCodeString.Append(" NestedLabels[" & IndexesToHide(i) & "].style.display = ""none"";" & vbCrLf)
Next
JScriptCodeString.Append(" } " & vbCrLf)
JScriptCodeString.Append(" </script> " & vbCrLf)
Return JScriptCodeString.ToString()
End Function
Here is the ASP.NET HTML source:
<body >
<form id="Form1" method="post" runat="server">
<P>Choose Gender (optional) : </P>
<P><asp:RadioButtonList id=rbGender runat="server" Width="200px" RepeatDirection="Horizontal">
<asp:ListItem Value="-1">-1</asp:ListItem>
<asp:ListItem Value="0">Female</asp:ListItem>
<asp:ListItem Value="1">Male</asp:ListItem>
</asp:RadioButtonList></P>
</form>
</body>
Here is the HTML source that is rendered to the browser when the page is run:
<body >
<form name="Form1" method="post" action="WebForm1.aspx" id="Form1">
<input type="hidden" name="__VIEWSTATE" value="dDwtMTQ2MTEwNDc7Oz5KPbuB9pD1EtgvbuBPmJmyEQ9ORQ==" ID="Hidden1"/>
<P>Choose Gender (optional) : </P>
<P><table id="rbGender" border="0" style="width:200px;">
<tr>
<td><input id="rbGender_0" type="radio" name="rbGender" value="-1" /><label for="rbGender_0">-1</label></td>
<td><input id="rbGender_1" type="radio" name="rbGender" value="0" /><label for="rbGender_1">Female</label></td>
<td><input id="rbGender_2" type="radio" name="rbGender" value="1" /><label for="rbGender_2">Male</label></td>
</tr>
</table></P>
<script language="javascript">
var rbTable;
rbTable = document.getElementById("rbGender");
if ((rbTable == null) || (rbTable == undefined)) { } else {
var NestedLabels;
NestedLabels = rbTable.getElementsByTagName("td");
NestedLabels[0].style.display = "none";
}
</script>
</form>
</body>
Basically, the code takes in a reference to a RadioButtonList and
uses its ClientID (the server control identifier generated by ASP.NET before the
control is rendered to the client's browser) property to access it
by using the document.getElementById Javascript function.
Then I determine if the repeat direction is Horizontal or Vertical and get
all columns or rows for the HTML element. Since the ListItem's indexes
match exactly to the collection of columns or rows in a rendered
RadioButtonList HTML table I am able to hide the rows or
columns based on the specified index the developer decides to pass in.
Hey what about the CheckBoxList?
I didn't forget about our good ol' friend the CheckboxList. In order to keep
this article concise I neglected to add the code for the CheckboxList. As
you might already know, these two controls are similar in that
they both have an Items collection and a RepeatDirection property. I
was hoping they both inherited from a BaseClass that would have these
two key properties. Unfortunately, the ListControl class from which they
inherit, has a Items collection property but doesn't have
a .RepeatDirection property. So I just decided to create seperate
overloaded methods for each of them.
When you download the source and project files you will see methods
devoted to both the CheckboxList and RadioButtonList in addition
to other cool ways of implementing this functionality into your
applications. Since I am well versed in both C# and
VB I have provided the source files in
both C# and VB.NET. So
you can just copy and paste as needed.
Conclusion
I hope this approach can benefit you if you need to hide or
show ListItems in a CheckboxList or RadioButtonList. Please feel free
to build upon this concept and extend it to create other functionality for
your individual ListItems. Some cool incarnations of this concept
could be disabling individual ListItems or adding custom
client-side onclick events.
Live long and code proper!
History
No revisions thus far...