Say you want to have a few radio buttons in the same group and want to do something when once is clicked. That is, you want to handle the JavaScript OnClick event,
You can try this:
<asp:RadioButtonList ID="costCenterIsCorrectRadioButtonList" RepeatDirection="Horizontal" runat="server" OnClick="alert(':( ... please work!')">
<asp:ListItem Text="Yes" Value="Yes" Selected="True"/>
<asp:ListItem Text="No" Value="No" />
</asp:RadioButtonList>
... and find that it's helpfully rendered on the containing element of the RadioButtonList, which is a table:
<table id="ctl00_DefaultContent_costCenterIsCorrectRadioButtonList" OnClick="alert('why!')" border="0"> ...
Ok, I'm smart, how about I try putting it on the List item:
<asp:ListItem Text="Yes" Value="Yes" Selected="True" onClick="alert('please work.. please!')"/>
That actually works, however this doesn't work too well if you need to dynamically set the value:
<asp:ListItem Text="Yes" Value="Yes" Selected="True" onClick="ToggleDisplay('<%=editCostCenterContainer.ClientID%>', this.selected)"/>
The above gets rendered like this
<input id="ctl00_DefaultContent_RadioButtonList1_0" type="radio" name="ctl00$DefaultContent$RadioButtonList1" value="Yes" checked="checked" onclick="ToggleDisplay('<%=editCostCenterContainer.ClientID%>', this.selected);" />
So another approach is creating those list items in the code behind:
ListItemCollection yesNoListItems = new ListItemCollection();
ListItem yesListItem = new ListItem("Yes", "Yes");
yesListItem.Attributes.Add("onClick", "ToggleDisplay('" + editCostCenterContainer.ClientID + "', this.selected)");
ListItem noListItem = new ListItem("No", "No");
noListItem.Attributes.Add("onClick", "ToggleDisplay('" + editCostCenterContainer.ClientID + "', this.selected)");
yesNoListItems.Add(yesListItem);
yesNoListItems.Add(noListItem);
costCenterIsCorrectRadioButtonList.DataSource = yesNoListItems;
costCenterIsCorrectRadioButtonList.DataBind();
But for some reason when you do this it doesn't render the onClick onto the Html input element, strange....
So the final approach, that actually works, is to create a control that derives from RadioButtonList and override the RenderItem method to add the OnClick to each html input, the actual specifics below are honed to my specific needs (particularly having the same onClick for each radio button, I imagine most cases may require it to be different, but that's fairly easy once you get it going), but you get the gist:
(UPDATE: there is more generic code example below.)
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SomeApp.Modules.Website.Controls
{
public class RadioButtonListWithOnChangeHook : RadioButtonList
{
private string _scriptToAmendToEachOptionsOnClick = String.Empty;
public string ScriptToAmendToEachOptionsOnClick
{
get { return _scriptToAmendToEachOptionsOnClick; }
set { _scriptToAmendToEachOptionsOnClick = value; }
}
protected override void RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
{
ListItem item = this.Items[repeatIndex];
string postbackCode = String.Empty;
writer.AddAttribute(HtmlTextWriterAttribute.Value, item.Value);
if(AutoPostBack)
postbackCode = Page.ClientScript.GetPostBackEventReference(this, String.Empty);
if (!String.IsNullOrEmpty(ScriptToAmendToEachOptionsOnClick))
postbackCode += ";" + ScriptToAmendToEachOptionsOnClick;
if (!String.IsNullOrEmpty(postbackCode))
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, postbackCode);
writer.AddAttribute(HtmlTextWriterAttribute.Id, UniqueID + IdSeparator + item.Value);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "radio");
writer.AddAttribute(HtmlTextWriterAttribute.Name, ClientID);
if (item.Selected)
writer.AddAttribute(HtmlTextWriterAttribute.Selected, "true");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.Write(item.Text);
writer.RenderEndTag();
}
}
}
Now include it on the code in front:
<%@ Register TagPrefix = "custom" Namespace = "SomeApp.Modules.Website.Controls" Assembly = "SomeApp.Modules.Website" %>
<custom:RadioButtonListWithOnChangeHook id="costCenterIsCorrectRadioButtonListWithOnChangeHook" runat="server">
<asp:ListItem Text="Yes" Value="Yes" Selected="True"/>
<asp:ListItem Text="No" Value="No" />
</custom:RadioButtonListWithOnChangeHook>
You could specify ScriptToAmendToEachOptionsOnClick (the prop on my custom control) via and attribute on the control in the .aspx or in my case in the code behind as it's a dynamic value:
costCenterIsCorrectRadioButtonListWithOnChangeHook.ScriptToAmendToEachOptionsOnClick = editCostCenterContainer.ClientID;
... and that's it, the value of ScriptToAmendToEachOptionsOnClick gets added to the OnClick of each radio button.
UPDATE:
The above ended up refactored to
the below for a more generic implementation which worked well for us:
using System;
using
System.Web.UI;
using
System.Web.UI.WebControls;
namespace ANameSpace
{
public abstract class
RadioButtonListWithOnClickHook : RadioButtonList
{
protected
abstract string
GetOnClickJavaScript(ListItem item);
protected
override void
RenderItem(ListItemType itemType, int
repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
{
ListItem item = Items[repeatIndex];
string
postbackCode = String.Empty;
writer.AddAttribute(HtmlTextWriterAttribute.Value, item.Value);
if
(AutoPostBack)
postbackCode =
Page.ClientScript.GetPostBackEventReference(this,
String.Empty);
string
customOnClick = GetOnClickJavaScript(item);
if
(!String.IsNullOrEmpty(postbackCode))
postbackCode += ";";
if (!String.IsNullOrEmpty(customOnClick))
postbackCode += customOnClick;
if
(!String.IsNullOrEmpty(postbackCode))
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, postbackCode);
writer.AddAttribute(HtmlTextWriterAttribute.Id,
ClientID + "_" + item.Value);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "radio");
writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
if
(item.Selected)
writer.AddAttribute(HtmlTextWriterAttribute.Selected,
"true");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.Write(item.Text);
writer.RenderEndTag();
}
}
}