//Friday, 21 March 2008

Validating a CheckBoxList with an ASP.NET validation control

If you try to use the standard ASP.NET validation controls to validate a CheckBoxList control you may receive an error message that looks like this:

Control 'CheckBoxList1' referenced by the ControlToValidate property of 'RequiredFieldValidator1' cannot be validated

Unfortunately out of the box the RequiredFieldValidator will not work on the CheckBoxList control. In a recent project I had a requirement to validate a number of checkbox lists. I needed to validate that at least one item was checked and in some cases make sure that no more than a certain number of options were selected. I created a new validator control specifically for validating CheckBoxLists to handle this.

Here is a demo of the control in action:


http://www.sourcemotion.com/CheckBoxListTest.aspx

Here is the source code for the validator control:

using System;
using System.Collections;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Validators
{
    public class CheckBoxListValidator : CustomValidator
    {
        private const string CheckBoxListValidatorScriptKey = "CheckBoxListValidator_GlobalScript";

        private bool _isRequired;

        private int _maximumChecked;

        private CheckBoxList _listctrl;

        public bool IsRequired
        {
            get
            {
                return this._isRequired;
            }
            set
            {
                this._isRequired = value;
            }
        }

        public int MaximumChecked
        {
            get
            {
                return this._maximumChecked;
            }
            set
            {
                this._maximumChecked = value;
            }
        }

        public CheckBoxListValidator()
        {
            this._isRequired = true;
            this._maximumChecked = -1;
        }

        protected override bool ControlPropertiesValid()
        {
            bool flag;
            Control control = this.FindControl(base.ControlToValidate);
            if (control == null)
            {
                flag = false;
            }
            else if (!(control is CheckBoxList))
            {
                flag = false;
            }
            else
            {
                this._listctrl = (CheckBoxList)control;
                if (base.EnableClientScript)
                {
                    this.Page.ClientScript.RegisterClientScriptBlock(base.GetType(), this.ClientID, this.GetScript(), true);
                    base.ClientValidationFunction = "validateCheckBoxList";
                }
                flag = true;
            }
            return flag;
        }

        protected override bool EvaluateIsValid()
        {
            bool flag;
            int num = 0;
            foreach (ListItem item in this._listctrl.Items)
            {
                if (item.Selected)
                {
                    num++;
                }
            }
            if ((num != 0 ? true : !this._isRequired))
            {
                flag = ((this._maximumChecked == -1 ? true : num <= this._maximumChecked) ? true : false);
            }
            else
            {
                flag = false;
            }
            return flag;
        }

        protected string GetScript()
        {
            string str = string.Format("var {0}_maxChecked = {1};\r\nvar {0}_isRequired = {2};\r\n", this._listctrl.ClientID, this._maximumChecked, this._isRequired.ToString().ToLower());
            return str;
        }

        protected string GetStartupScript()
        {
            return string.Format("fixCheckboxValidationEvent('{0}');\r\n", this._listctrl.ClientID);
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if ((!base.EnableClientScript ? false : !this.Page.ClientScript.IsClientScriptBlockRegistered(this.Page.GetType(), "CheckBoxListValidator_GlobalScript")))
            {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("function fixCheckboxValidationEvent(id)");
                stringBuilder.AppendLine("{");
                stringBuilder.AppendLine("    if (document.getElementById(id))");
                stringBuilder.AppendLine("    {");
                stringBuilder.AppendLine("        var checkboxList = document.getElementById(id);");
                stringBuilder.AppendLine("        if (checkboxList.getElementsByTagName)");
                stringBuilder.AppendLine("        {");
                stringBuilder.AppendLine("             var inputs = checkboxList.getElementsByTagName(\"input\");");
                stringBuilder.AppendLine("             for (j=0;j<inputs.length;j++)");
                stringBuilder.AppendLine("             {");
                stringBuilder.AppendLine("                 if (inputs[j].type.toLowerCase()==\"checkbox\")");
                stringBuilder.AppendLine("                 {");
                stringBuilder.AppendLine("                     inputs[j].onclick = inputs[j].onchange;");
                stringBuilder.AppendLine("                     inputs[j].onchange = null;");
                stringBuilder.AppendLine("                 }");
                stringBuilder.AppendLine("             }");
                stringBuilder.AppendLine("        }");
                stringBuilder.AppendLine("    }");
                stringBuilder.AppendLine("}");
                stringBuilder.AppendLine("");
                stringBuilder.AppendLine("function validateCheckBoxList(val, args)");
                stringBuilder.AppendLine("{");
                stringBuilder.AppendLine("    var selectedCount = 0;");
                stringBuilder.AppendLine("    if (document.getElementById(val.controltovalidate))");
                stringBuilder.AppendLine("    {");
                stringBuilder.AppendLine("        var checkboxList = document.getElementById(val.controltovalidate);");
                stringBuilder.AppendLine("        if (checkboxList.getElementsByTagName)");
                stringBuilder.AppendLine("        {");
                stringBuilder.AppendLine("            var inputs = checkboxList.getElementsByTagName(\"input\");");
                stringBuilder.AppendLine("            for (j=0;j<inputs.length;j++)");
                stringBuilder.AppendLine("            {");
                stringBuilder.AppendLine("                if (inputs[j].type.toLowerCase()==\"checkbox\")");
                stringBuilder.AppendLine("                {");
                stringBuilder.AppendLine("                    if (inputs[j].checked)");
                stringBuilder.AppendLine("                    {");
                stringBuilder.AppendLine("                        selectedCount++;");
                stringBuilder.AppendLine("                    }");
                stringBuilder.AppendLine("                }");
                stringBuilder.AppendLine("            }");
                stringBuilder.AppendLine("        }");
                stringBuilder.AppendLine("        var maxCount = eval(val.controltovalidate + \"_maxChecked\");");
                stringBuilder.AppendLine("        var isRequired = eval(val.controltovalidate + \"_isRequired\");");
                stringBuilder.AppendLine("        if (selectedCount == 0 && isRequired)");
                stringBuilder.AppendLine("        {");
                stringBuilder.AppendLine("            args.IsValid = false;");
                stringBuilder.AppendLine("        } ");
                stringBuilder.AppendLine("        else if ((maxCount > -1) && (selectedCount > maxCount)) ");
                stringBuilder.AppendLine("        {");
                stringBuilder.AppendLine("            args.IsValid = false;");
                stringBuilder.AppendLine("        } ");
                stringBuilder.AppendLine("        else ");
                stringBuilder.AppendLine("        {");
                stringBuilder.AppendLine("            args.IsValid = true;");
                stringBuilder.AppendLine("        }");
                stringBuilder.AppendLine("    }");
                stringBuilder.AppendLine("}");
                this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "CheckBoxListValidator_GlobalScript", stringBuilder.ToString(), true);
            }
            if ((!base.EnableClientScript ? false : !this.Page.ClientScript.IsStartupScriptRegistered(base.GetType(), this.ClientID)))
            {
                this.Page.ClientScript.RegisterStartupScript(base.GetType(), this.ClientID, this.GetStartupScript(), true);
            }
        }
    }
}

Notes:

  • In the CheckBoxListValidator class I override the ControlPropertiesValid method. This is the method that normally throws an exception if you try to assign a CheckboxList control to the ControlToValidate property of a RequiredFieldValidator control. This method now checks to ensure that the ControlToValidate property is pointing at a CheckboxList control.
  • The Javascript function fixCheckboxValidationEvent gets called for each CheckBoxList control and swaps the standard client validation function from the onchange event to the onclick event. By default validation is called on change but for the checkbox you actually need it on click.

2 comments:

DennisWong said...

Hi Steve,

It's not working. Sorry, I may not have implemented this properly.

This is what I did:

1. Copy and pasted your code into my "App_Code" folder, and created a new file called CheckBoxListValidator.vb.
(I converted it to vb).

2. Then in my aspx page, I added the directive on top :
Register Assembly="Validators" Namespace="Validators" TagPrefix="c1"

3. Error : Can't find the assembly or file.

4. Then I removed this, and used your instructions to create a normal RequiredFieldValidator... But error : ...cannot be validated.

Please help.

Steve Sage said...

In my example the project is a Web Application Project rather than a website project. This means I can reference the web application assembly in the Register directive. If you are using a website project the easiest thing to do is to create a class library called Validators in your solution. Move CheckBoxListValidators.vb to the class library (you'll need to add a reference to System.Web). Then add a reference in your website to the Validators assembly.

SyntaxHighlighter