Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Cross-Validate Checkboxes in .NET

3.46/5 (5 votes)
28 Nov 20075 min read 1   239  
Use both client-side and server-side validation across multiple checkboxes
Screenshot - Three checkboxes and a submit button

Introduction

The .NET Framework provides for both client-side and server-side validation. Client-side validation can avoid the time involved in sending a form to the server, only to have it rejected because of a validation error. It can notify the user of errors very quickly. Client-side cross-validation of multiple checkboxes is problematic because of when the .NET Framework does client-side validation. Unless the programmer gives particular attention to checkbox validation, the user may see messages that appear to respond to exactly the opposite of what he is doing.

A Solution to the Problem

The Framework does client-side validation when the Change event occurs. This occurs after the user has finished making any changes to the value of the control and moves focus elsewhere. The problem occurs when "elsewhere" is to another checkbox in the set of checkboxes being validated. Consider the following scenario: The validation rule is that at least one of two adjacent checkboxes must be checked. The script implementing this rule is set up to run for both checkboxes. Assume that the second checkbox starts out unchecked and that the user has just unchecked the first one and has clicked the second one to check it. The user will immediately see a check appear in the second box. Since clicking the second box causes the first box to lose focus, the validation script for the first box will run. Since the user has just unchecked the first box, the validation script will find it unchecked. The script is running in response to the first box's Change event, triggered by the focus switching to the second checkbox. At the moment of the focus change, the validation script finds the second box unchecked. Validation fails, and the user gets an error message. But from the user's point of view, this is wrong, since what he sees is that he has just checked the second box. The message says that neither is checked, but the user sees the check mark in the second box. Had the first box lost focus by the user putting it elsewhere, the result of the validation would make a lot more sense to the user.

It's important, then, to make sure that focus on one checkbox isn't lost as a result of the user checking a different box. The approach that I present here is to cause validation on a Mouseout event, causing the validation to occur before the user has a chance to click the other checkbox. Checkboxes may have associated labels, clicks on which also cause the checkbox status to toggle. The code presented here also handles these labels.

The technique used to force validation should not change focus to another control, as this would confuse the tab order. The technique presented here raises a Blur event on the checkbox control, causing the validation script to run, and then focuses once again on the checkbox itself.

Using the Code

Here's the code that you'll need to add to your page to implement this validator. This sample verifies that at least one of three checkboxes is checked. The names of the controls appear in both the client-side and server-side validation functions. You will have to modify these functions to use the names of your checkbox controls.

Put this script at the top of your page after the <meta> tags. If you are validating within a user control, put it at the top of the control page. The first function is the client-side validator. The second causes a focus change when the mouse leaves the checkbox that is to be validated.

JavaScript
<script type="text/javascript" language="javascript">

    function AtLeastOneCheckbox_ClientValidate(source, args)
    {
        // Requires that In Progress, Complete, and/or Cancelled is checked
        args.IsValid = 
            document.getElementById("<%=cbxInProgress.ClientID %>").checked
          || document.getElementById("<%=cbxComplete.ClientID %>").checked
          || document.getElementById("<%=cbxCancelled.ClientID %>").checked;
    }

    /* Causes validation if mouse is moved out of control with focus 
    or its label (if there is a validator) */
    function BlurThenRefocus()
    {
        if(document.activeElement == window.event.srcElement
        || window.event.srcElement.nodeName == 'LABEL'
             && document.activeElement.id == window.event.srcElement.htmlFor)
        {
            document.activeElement.blur();
            if(window.event.srcElement.nodeName == 'LABEL')
            {
                document.getElementById
                    (window.event.srcElement.htmlFor).focus();
            }
            else
            {
                window.event.srcElement.focus();
            }
        }
    }

</script>    

In your checkbox definitions, specify BlurThenRefocus() as the onMouseOut event handler. Add the custom validator where you would like the error message to be displayed. Here's an example of three validated checkboxes followed by a CustomValidator for the boxes. The ClientValidatorFunction refers to the AtLeastOneCheckbox_ClientValidate function defined above. The OnServerValidate function will be defined in the server-side code below.

ASP.NET
<asp:checkbox id="cbxInProgress" Runat="server" 
    Text="In Progress" tabIndex="1" onmouseout="BlurThenRefocus()">
</asp:checkbox>  
<asp:checkbox id="cbxComplete" Runat="server" Text="Complete" 
    tabIndex="2" onmouseout="BlurThenRefocus()">
</asp:checkbox>  
<asp:checkbox id="cbxCancelled" Runat="server" Text="Cancelled" 
    tabIndex="3" onmouseout="BlurThenRefocus()">
</asp:checkbox>  
<asp:CustomValidator id="AtLeastOneCheckbox" runat="server"
    ErrorMessage="Check at least one status"
    Display="Dynamic"
    OnServerValidate="AtLeastOneCheckbox_ServerValidate"
    ClientValidationFunction="AtLeastOneCheckbox_ClientValidate" /> 

Next we cause this CustomValidator to be executed when the value of any of the three checkboxes is changed. Add the code below just before the </form> tag at the bottom of the page or at the very bottom of the user-control page. It associates the CustomValidator with each of the checkboxes. This is done instead of specifying a ControlToValidate in the CustomValidator definition above, since it will validate three different controls.

JavaScript
<script type="text/javascript">

  ValidatorHookupControlID("<%= cbxInProgress.ClientID %>",
     document.getElementById("<%= AtLeastOneCheckbox.ClientID %>"));
  ValidatorHookupControlID("<%= cbxComplete.ClientID %>",
     document.getElementById("<%= AtLeastOneCheckbox.ClientID %>"));
  ValidatorHookupControlID("<%= cbxCancelled.ClientID %>",
     document.getElementById("<%= AtLeastOneCheckbox.ClientID %>"));

</script>

All that's left now is to define the server-side validation function. It returns its result in its second argument. Put this code where you define your server-side methods.

C#
public void AtLeastOneCheckbox_ServerValidate
    (object source, ServerValidateEventArgs args)
{
    // Requires that In Progress, Complete, and/or Cancelled is checked
    args.IsValid = cbxInProgress.Checked || cbxComplete.Checked 
        || cbxCancelled.Checked;
}

Running the Example Project

The example contains three checkboxes, a Submit button, and a Validation Summary box. When you first run the program, you will notice that as you pass the cursor over the checkboxes, no messages appear. This is because validation is performed only when the status of a box changes. However, if you click the Submit button, the server-side validation code will run, displaying the validation error. Once you have changed the status of a checkbox, however, the status messages that you will see (or the removal thereof) are the results of client-side validation. The example's Validation Summary box exists only to help you tell whether the client-side or the server-side validation is presenting or clearing the message. Only the server-side validation function writes into the summary box. If client-side validation fails, clicking the Submit button will not result in a page post-back to the server.

You may wish to experiment with using the Tab key and the space bar on your keyboard to navigate the page and change the status of the checkboxes.

Sources

The technique that I use for applying common validation to several controls comes from the article CustomValidator dependent on multiple controls by DanielHac.

History

  • 11/27/2007: Original article

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here