I have a radio button list in asp.net like
<asp:RadioButtonList ID="rblChoose" runat="server" RepeatDirection="Horizontal"
RepeatLayout="Flow">
<asp:ListItem Text="a" Value="a" />
<asp:ListItem Text="b" Value="b" />
</asp:RadioButtonList>
<asp:RequiredFieldValidator ID="rfvChoose" runat="server"
ControlToValidate="rblChoose" ErrorMessage="Choose registration option."
ForeColor="red" SetFocusOnError="true"></asp:RequiredFieldValidator>
When the RequiredFieldValidator
shows the client message on error it is focusing the last RadioButton
in the list. Why is it setting the focus on the last RadioButton
in list. I would like to focus on the first RadioButton
on error.
The reason why this is happening as the generated HTML for the radio button will look similar to this. (Note the names \ ids will be changed to suit the application and heirchy).
<span id="MainContent_rblChoose"><span name="rblChoosea">
<input id="MainContent_rblChoose_0" type="radio" name="ctl00$MainContent$rblChoose" value="a">
<label for="MainContent_rblChoose_0">a</label></span><span name="rblChooseb">
<input id="MainContent_rblChoose_1" type="radio" name="ctl00$MainContent$rblChoose" value="b">
<label for="MainContent_rblChoose_1">b</label>
</span>
Now what is important is if you look at the name
attribute. The names are the same as (for radiobuttons) so they correctly toggle between each other. This also sets which value is posted in the form event.
Now the default validator (if you dig through the MS javascript) eventually calls the following snippet.
var inputElements = ctrl.getElementsByTagName("input");
var lastInputElement = inputElements[inputElements.length -1];
if (lastInputElement != null) {
ctrl = lastInputElement;
}
If you review the code above you will notice that it actually gets the lastInputElement
from the array of elements that match the element name and have a tag name of input
. Therefore when the code executes to focus the ctrl
it is focusing on the last
element (as you see in your validation).
Now we know thats the default behavior, what we also need to know is how do we overcome this problem. Well thats where you will have to stay away from the RequiredFieldValidator
control and write your own CustomValidator
with a custom javascript function. Now this is quite simple and is only really valid for this case but can be done with a few lines of code.
First off you define your CustomValidator
as such (example only).
<asp:CustomValidator runat="server"
ID="rfvChoose"
ErrorMessage="Choose registration option."
EnableClientScript="true"
ForeColor="Red"
ClientValidationFunction="rfvChooseValidator" />
Noticing another property enabled of ClientValidationFunction
this is a javascript function that will set the IsValid
property to true
\ false
based on a set of conditions. The javascript is then quite easy to implement. Note in my example I have added special events to hide the validation message after a radio button is selected. I put alot of comments in the javascript so you can understand exactly what each stage does.
<script type="text/javascript">
//function called when the rfvChoose validator is called
function rfvChooseValidator(sender, args) {
//set the object id for the radio button list
var objID = '#<%= rblChoose.ClientID %>';
//set the is valid flag by evaluating if any radio buttons in the radiobutton list are selected (using the psudo selector :checked)
args.IsValid = $(objID + ' input[type="radio"]:checked').size() > 0;
if (args.IsValid) {
//if the validation is succesful remove the eventValidation custom click handler
$(objID + ' input[type="radio"]').off('click.eventValidator');
//hide the validation message
$('#<%= rfvChoose.ClientID %>').css('visibility', 'hidden');
}
else {
//focus the first radiobutton in the list
$(objID + ' input[type="radio"]:first').focus();
//if the arguments are not valid set an event handler to trigger when any of the radio buttons are selected
// the custom click event handler uses the .eventValidator namespace so we can on\off just the click handler for event validation
// thus leaving all other click events enabled
$(objID + ' input[type="radio"]').off('click.eventValidator')
.on('click.eventValidator', function () {
//this simply recalls the validation function with a null sender and a blank object for the args
// note the blank object is set using {} as opposed to null so in the callback we can set a property
// of this blank object. Passing null will cause an exception when trying to set a value.
rfvChooseValidator(null, {});
});
}
}
</script>
Simply put the javascript function above will be executed every time the CustomValidator
client validation events are raised.
Now I realize in the bounty statement that you only want to use a RequiredFieldValidator
however this wont be possible if you would like to focus the first control
UPDATE
If you wish to change the DisplayType
to Dynamic
you must change the line
$('#<%= rfvChoose.ClientID %>').css('visibility', 'hidden');
TO
$('#<%= rfvChoose.ClientID %>').css('display', 'none');
Or you can replace the code with the following snippet to auto-detect the display type and set the display\ visibility css accordingly.
//identify the display type
var displayType = $('#<%= rfvChoose.ClientID %>').data('val-display');
if (displayType === undefined || displayType == null || displayType == 'Static')
displayType = { 'visibility': 'hidden' };
else
displayType = { 'display': 'none' };
//hide the validation message
$('#<%= rfvChoose.ClientID %>').css(displayType);