First time here? You are looking at the most recent posts. You may also want to check out older archives or the tag cloud. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS. Thank you for visiting! (hide this)

If you add a normal RequiredFieldValidator and you want to validate a CheckBoxList, you will get a runtime exception informing you that the CheckBoxList cannot be validated.

Sometimes you want to make sure the that user has selected at least one of the checkbox in the checkbox list, but as aforementioned, if you user a normal RequiredFieldValidator you will get an exception.

You could use a CustomValidator control, but a nicer and more reusable approach is to build a custom web control that extends the BaseValidator.

I found a 2001 article on how to do that (Building a CheckBoxList Validator Control) but it doesn't work properly on ASP.NET 2.0 and also it doesn't work on Firefox.

So I have to make some small changes to make it work on ASP.NET 2.0 and on Firefox.

First thing you have create a class that inherits from BaseValidator

public class RequiredFieldValidatorForCheckBoxLists : BaseValidator

Then you have to override a few methods:

ControlPropertiesValid

This method must check whether the ControlToValidate property of the validator refers to an existing control and if the control is of the correct type

protected override bool ControlPropertiesValid()
{
   Control ctrl = FindControl(ControlToValidate);
   if (ctrl != null)
   {
      CheckBoxList _listctrl = ctrl as CheckBoxList;
      return (_listctrl != null);
   }
   else
      return false;  
}

In this we check if the control is null and if the control can be cast to a CheckBoxList.

EvaluateIsValid

This is the methods that performs the server side validation in case JavaScript is not enabled on the client, or not supported.

protected override bool EvaluateIsValid()
{
   return EvaluateIsChecked();
}

// Private method to perform the real check
private bool EvaluateIsChecked()
{
   CheckBoxList _cbl = ((CheckBoxList)FindControl(ControlToValidate));
   foreach (ListItem li in _cbl.Items)
   {
      if (li.Selected)
      {
         return true;
      }
   }
   return false;
}

In this method I just loop through all the items of the CheckBoxList and if I find one that is selected then I return true.

Now we have the validation working on the server after a postback, but it would be nice if we could perform the validation directly on the client when the user toggles the state of the checkboxes. To accomplish this there is another step to take: inject some client side JavaScript in the OnPreRender method.

OnPreRender

The PreRender event is raised just before the control is rendered on the page, so it the best moment to inject some client side functionality into the page.

protected override void OnPreRender(EventArgs e)
{
   base.OnPreRender(e);
   if (EnableClientScript) { ClientScript(); }
}

private void ClientScript()
{
   StringBuilder sb_Script = new StringBuilder();
   sb_Script.Append("<script language=\"javascript\">");
   sb_Script.Append("\r");
   sb_Script.Append("\r");
   sb_Script.Append("function cb_verify(sender) {");
   sb_Script.Append("\r");
   sb_Script.Append("var val = document.getElementById(document.getElementById"
			+"(sender.id).controltovalidate);");
   sb_Script.Append("\r");
   sb_Script.Append("var col = val.getElementsByTagName(\"*\");");
   sb_Script.Append("\r");
   sb_Script.Append("if ( col != null ) {");
   sb_Script.Append("\r");
   sb_Script.Append("for ( i = 0; i < col.length; i++ ) {");
   sb_Script.Append("\r");
   sb_Script.Append("if (col.item(i).tagName == \"INPUT\") {");
   sb_Script.Append("\r");
   sb_Script.Append("if ( col.item(i).checked ) {");
   sb_Script.Append("\r");
   sb_Script.Append("\r");
   sb_Script.Append("return true;");
   sb_Script.Append("\r");
   sb_Script.Append("}");
   sb_Script.Append("\r");
   sb_Script.Append("}");
   sb_Script.Append("\r");
   sb_Script.Append("}");
   sb_Script.Append("\r");
   sb_Script.Append("\r");
   sb_Script.Append("\r");
   sb_Script.Append("return false;");
   sb_Script.Append("\r");
   sb_Script.Append("}");
   sb_Script.Append("\r");
   sb_Script.Append("}");
   sb_Script.Append("\r");
   sb_Script.Append("</script>");

   //Inject the script into the page
   Page.ClientScript.RegisterClientScriptBlock(GetType(), SCRIPTBLOCK,
					sb_Script.ToString());
   //Registering validator clientside javascript function
   Page.ClientScript.RegisterExpandoAttribute(ClientID, "evaluationfunction",
					"cb_verify");
}

First I check if the client validation is enabled, and, if it is, I write on the page the javascript method, and more important, the code to tell the common validation script to call my "cb_verify" function to validate the value of the control.

If you do a "View Source" on an ASP.NET page you will see something like this:

var validator = document.all ? document.all["validator"] :
		document.getElementById("validator");
validator.controltovalidate = "answer";
validator.isvalid = "False";
validator.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";

These lines add custom properties to the validators registered on the page, so we have to do the same also to specify the function name used to validate the CheckBoxList, using the RegisterExpandoAttribute method:

Page.ClientScript.RegisterExpandoAttribute(ClientID, "evaluationfunction",
					"cb_verify");

which will add the following code to the page:

checkboxListValidator.evaluationfunction = "cb_verify";

Add the RequiredFieldValidatorForCheckBoxLists to the page

Register the control and then add it to the page

<%@ Register TagPrefix="CC1" Namespace="Custom.Validators"
    Assembly="Custom.Validators" %>

<CC1:RequiredFieldValidatorForCheckBoxLists
    ControlToValidate="answers"
    runat="server"
    ID="checkboxListvalidator">*
</CC1:RequiredFieldValidatorForCheckBoxLists>

Download the complete file

Here is the complete RequiredFieldValidatorForCheckBoxLists.cs file, also without all the extra new lines I added above to make long lines fit into the width of the main column.

Technorati tags: , ,
posted on Thursday, July 19, 2007 3:55 PM

Comments on this entry:

# re: How to add a required validator to a CheckBoxList

Left by Ted Jardine at 7/19/2007 5:45 PM

Thanks for the write up above, but personally, I look no further than using Peter Blum's VAM controls (www.peterblum.com). Aside from providing cross-browser validators of all kinds, out of the box it provides so much more: ASP.NET AJAX capable, extra validation notification goodies that are a snap to implement (i.e. css styles applied to non-valid fields, validation summary direct links to specified invalid fields, and so on and so forth), dead easy disable on submit buttons, unparalleled support, and so much more I'm not remembering to mention right now.

You can implement many of the above yourself (while much other PeterBlum functionality remains time/effort/skill prohibitive to duplicate), but using a fraction of the time and effort you can implement with all the nice finishing touches included as a bonus.

Well worth it.

# re: How to add a required validator to a CheckBoxList

Left by Simone at 7/19/2007 6:01 PM

Agree, if you need to perform a lot of stuff, then using a 3rd party control library is good, but I only needed that one, and it took me less than half a day to look for a solution on Google, adapt it for my needs, test it, and write a blog post about it, so less then the cost of the single webserver license.
And then I adapted the same thing also for list of Ratings controls inside the ASP.NET AjaxControlToolkit, which I would have had to implement myself anyway.

# re: How to add a required validator to a CheckBoxList

Left by Ted Jardine at 7/19/2007 6:06 PM

Unfortunately, the one thing about Peter Blum's stuff is that his site is a little hard to follow. The checkboxlist validator is a part of the VAM Essential Validators Module (http://peterblum.com/VAM/EssentialValidators.aspx?ReturnUrl=Home.aspx%23Essential).

This module is only $50 (US) per server, while a site license is $250 (US), and Redistribution License $500 (US) (see all pricing at http://peterblum.com/VAM/Commercial.aspx).

And I'm thinking you're making more than $12.50/hr ;-) But if you aren't, consider yourself hired!

And I'll sign off now before I sound any more like a door to door salesman.

# re: How to add a required validator to a CheckBoxList

Left by Simone at 7/19/2007 6:14 PM

I see you are from BC, Canada... if that will get me a Visa to work in BC then I'll send you my CV :-)
Anyway, I think you have to compare it with the Redist License since now I can you my validator in all the sites I'm going to make for the rest of my life :)

# re: How to add a required validator to a CheckBoxList

Left by Tim at 7/20/2007 1:39 AM

That is way too much work to validate a checkbox. I abandoned the .net validation controls a long time ago because of these bugs and rolled my own javascript validation class that uses custom attributes on the tags themselves. I haven't run into very many issues doing it this way. http://www.techtoolblog.com/archives/javascript-generic-form-validation

# re: How to add a required validator to a CheckBoxList

Left by Ted Jardine at 7/21/2007 7:10 AM

Lol. All I can say is give Peter Blum a try and you won't go back. However, if you still insist, you're more than welcome to continue rolling your own (including any other validators you need, or needing them to work with ASP.NET AJAX now, or...) ;-)

As to working in British Columbia, Canada: if you're serious, I'm serious in asking for you to send your CV. There's a few mountains here you might like ;-)

As you're Italian, it's too bad you just missed the FIFA U-20.

# re: How to add a required validator to a CheckBoxList

Left by Simone at 7/21/2007 9:37 AM

Anyway, I don't think I'm going to roll my own validation library: I only needed that specific validation, as in all my previous 6 years of .NET development I always used the ASP.NET validators without any problem.

Not really serious about working in BC, but I'm considering any option, so might send you my CV anyway ;-)

I'm Italian, but I don't like soccer, so not a big deal having missed the U-20 tournament

# re: How to add a required validator to a CheckBoxList

Left by Matt at 7/24/2007 12:37 AM

minor nitpick:

Seems this:
CheckBoxList _listctrl = (CheckBoxList)ctrl;
return (_listctrl != null);


should be:


CheckBoxList _listctrl = ctrl as CheckBoxList;
return (_listctrl != null);

The former will throw ClassCastException on failure to cast, the latter will just return null. Seems more appropriate since you are checking for null on the next line and using that as a failure indicator.

# re: How to add a required validator to a CheckBoxList

Left by Matt at 7/24/2007 12:41 AM

InvalidCastException, of course. My Java roots come out sometimes :)

# re: How to add a required validator to a CheckBoxList

Left by Simone at 7/24/2007 9:26 AM

Thank you Matt for pointing it out.
I always tested it with a Checkbox, so never got the exception.

# re: How to add a required validator to a CheckBoxList

Left by Steven Harman at 8/7/2007 6:26 AM

>>I always tested it with a Checkbox, so never got the exception.

Your unit tests should have caught that Simo. Shame on you! :)

# re: How to add a required validator to a CheckBoxList

Left by Simone at 8/9/2007 3:18 AM

:-P

Comments have been closed on this topic.