115

I've done some searching on this, and I've found several partial answers, however nothing that gives me that warm fuzzy "this is the right way to do this". To answer the most frequently occurring complaint against this question: "checkboxes can have two legitimate states - checked and unchecked", this is an "I accept the terms and conditions..." checkbox which must be checked in order to complete a registration, hence checking the box is required from a business logic standpoint.

Please provide complete cut-n-paste ready code fragments with your response! I know there are several pieces to this -- the CustomValidator (presumably), the code-behind, some javascript and possibly a check for IsValid, and the frustrating part for me is that in each example I've seen, one of these critical pieces is missing!

Bob Kaufman
  • 12,864
  • 16
  • 78
  • 107

6 Answers6

220

javascript function for client side validation (using jQuery)...

function CheckBoxRequired_ClientValidate(sender, e)
{
    e.IsValid = jQuery(".AcceptedAgreement input:checkbox").is(':checked');
}

code-behind for server side validation...

protected void CheckBoxRequired_ServerValidate(object sender, ServerValidateEventArgs e)
{
    e.IsValid = MyCheckBox.Checked;
}

ASP.Net code for the checkbox & validator...

<asp:CheckBox runat="server" ID="MyCheckBox" CssClass="AcceptedAgreement" />
<asp:CustomValidator runat="server" ID="CheckBoxRequired" EnableClientScript="true"
    OnServerValidate="CheckBoxRequired_ServerValidate"
    ClientValidationFunction="CheckBoxRequired_ClientValidate">You must select this box to proceed.</asp:CustomValidator>

and finally, in your postback - whether from a button or whatever...

if (Page.IsValid)
{
    // your code here...
}
Chris
  • 39,719
  • 45
  • 189
  • 235
Scott Ivey
  • 40,768
  • 21
  • 80
  • 118
  • I'm probably doing something wrong. I'll continue to investigate at my end, however ControlToValidate="" throws exception "Control referenced by ControlToValidate property cannot be validated." Which breaks the javascript, etc. – Bob Kaufman Aug 04 '09 at 16:17
  • 2
    ahh, right. Just remove that - CheckBox doesn't implement the correct interface to tie it up. The validator will still run fine without that property set. I'll update my example accordingly. – Scott Ivey Aug 04 '09 at 16:18
  • 2
    The CustomValidator parameter for the javascript function name should be 'ClientValidationFunction', not 'OnClientValidate'. See: http://msdn.microsoft.com/en-us/library/9eee01cx(v=VS.100).aspx – Chris Nov 25 '10 at 23:01
  • 1
    I would suggest using `jQuery("#<%= MyCheckBox.ClientID %>")` instead of `jQuery(".AcceptedAgreement input:checkbox")` to be more explicit in which element you are attempting to affect. – Jesse Webb Jul 10 '14 at 17:09
  • You can use `e.IsValid = document.getElementsByClassName('AcceptedAgreement')[0].childNodes[0].checked;` if you don't want to use jquery. and you might want to add `ValidationGroup="valGroup"`. – Luke Alderton Oct 16 '14 at 14:12
  • 3
    I did not initially notice that there is no ControlToValidate attribute. Including this attribute causes an exception, so a word of warning to others who may also miss that. – MicrosoftAccessPros.com Jul 24 '15 at 18:36
  • Worked for me only when i added same ValidationGroup property to checkbox and validator. – Tone Škoda Sep 22 '15 at 12:17
  • The problem with this is that the validator message does not disappear if you submit w/o checking the box, then try and check the box. – MC9000 Sep 19 '18 at 12:27
19

C# version of andrew's answer:

<asp:CustomValidator ID="CustomValidator1" runat="server" 
        ErrorMessage="Please accept the terms..." 
        onservervalidate="CustomValidator1_ServerValidate"></asp:CustomValidator>
    <asp:CheckBox ID="CheckBox1" runat="server" />

Code-behind:

protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
    args.IsValid = CheckBox1.Checked;
}
John Rasch
  • 62,489
  • 19
  • 106
  • 139
13

If you want a true validator that does not rely on jquery and handles server side validation as well ( and you should. server side validation is the most important part) then here is a control

public class RequiredCheckBoxValidator : System.Web.UI.WebControls.BaseValidator
{
    private System.Web.UI.WebControls.CheckBox _ctrlToValidate = null;
    protected System.Web.UI.WebControls.CheckBox CheckBoxToValidate
    {
        get
        {
            if (_ctrlToValidate == null)
                _ctrlToValidate = FindControl(this.ControlToValidate) as System.Web.UI.WebControls.CheckBox;

            return _ctrlToValidate;
        }
    }

    protected override bool ControlPropertiesValid()
    {
        if (this.ControlToValidate.Length == 0)
            throw new System.Web.HttpException(string.Format("The ControlToValidate property of '{0}' is required.", this.ID));

        if (this.CheckBoxToValidate == null)
            throw new System.Web.HttpException(string.Format("This control can only validate CheckBox."));

        return true;
    }

    protected override bool EvaluateIsValid()
    {
        return CheckBoxToValidate.Checked;
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        if (this.Visible && this.Enabled)
        {
            System.Web.UI.ClientScriptManager cs = this.Page.ClientScript;
            if (this.DetermineRenderUplevel() && this.EnableClientScript)
            {
                cs.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", "cb_verify", false);
            }
            if (!this.Page.ClientScript.IsClientScriptBlockRegistered(this.GetType().FullName))
            {
                cs.RegisterClientScriptBlock(this.GetType(), this.GetType().FullName, GetClientSideScript());
            } 
        }
    }

    private string GetClientSideScript()
    {
        return @"<script language=""javascript"">function cb_verify(sender) {var cntrl = document.getElementById(sender.controltovalidate);return cntrl.checked;}</script>";
    }
}
CirrusABS
  • 131
  • 1
  • 2
  • This is the only answer which will work on more than one CheckBox in a form, rather than needing 1 function per each object. Huzzah! – haliphax Oct 05 '15 at 14:40
  • Thank you very much. I needed a way to do this with multiple dynamically rendered controls. Awesome. – schmosef Aug 12 '16 at 05:01
  • While the selected solution from Scott is correct/valid, I believe this is the more complete solution. This custom control should have been baked in to the framework. Thanks CirrusABS! – Gabe Jul 19 '18 at 15:32
6

Scott's answer will work for classes of checkboxes. If you want individual checkboxes, you have to be a little sneakier. If you're just doing one box, it's better to do it with IDs. This example does it by specific check boxes and doesn't require jQuery. It's also a nice little example of how you can get those pesky control IDs into your Javascript.

The .ascx:

<script type="text/javascript">

    function checkAgreement(source, args)
    {                
        var elem = document.getElementById('<%= chkAgree.ClientID %>');
        if (elem.checked)
        {
            args.IsValid = true;
        }
        else
        {        
            args.IsValid = false;
        }
    }

    function checkAge(source, args)
    {
        var elem = document.getElementById('<%= chkAge.ClientID %>');
        if (elem.checked)
        {
            args.IsValid = true;
        }
        else
        {
            args.IsValid = false;
        }    
    }

</script>

<asp:CheckBox ID="chkAgree" runat="server" />
<asp:Label AssociatedControlID="chkAgree" runat="server">I agree to the</asp:Label>
<asp:HyperLink ID="lnkTerms" runat="server">Terms & Conditions</asp:HyperLink>
<asp:Label AssociatedControlID="chkAgree" runat="server">.</asp:Label>
<br />

<asp:CustomValidator ID="chkAgreeValidator" runat="server" Display="Dynamic"
    ClientValidationFunction="checkAgreement">
    You must agree to the terms and conditions.
    </asp:CustomValidator>

<asp:CheckBox ID="chkAge" runat="server" />
<asp:Label AssociatedControlID="chkAge" runat="server">I certify that I am at least 18 years of age.</asp:Label>        
<asp:CustomValidator ID="chkAgeValidator" runat="server" Display="Dynamic"
    ClientValidationFunction="checkAge">
    You must be 18 years or older to continue.
    </asp:CustomValidator>

And the codebehind:

Protected Sub chkAgreeValidator_ServerValidate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ServerValidateEventArgs) _
Handles chkAgreeValidator.ServerValidate
    e.IsValid = chkAgree.Checked
End Sub

Protected Sub chkAgeValidator_ServerValidate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ServerValidateEventArgs) _
Handles chkAgeValidator.ServerValidate
    e.IsValid = chkAge.Checked
End Sub
jorelli
  • 8,064
  • 4
  • 36
  • 35
5

I typically perform the validation on the client side:

<asp:checkbox id="chkTerms" text=" I agree to the terms" ValidationGroup="vg" runat="Server"  />
<asp:CustomValidator id="vTerms"
                ClientValidationFunction="validateTerms" 
                ErrorMessage="<br/>Terms and Conditions are required." 
                ForeColor="Red"
                Display="Static"
                EnableClientScript="true"
                ValidationGroup="vg"
                runat="server"/>

<asp:Button ID="btnSubmit" OnClick="btnSubmit_Click" CausesValidation="true" Text="Submit" ValidationGroup="vg" runat="server" />

<script>
    function validateTerms(source, arguments) {
        var $c = $('#<%= chkTerms.ClientID %>');
        if($c.prop("checked")){
            arguments.IsValid = true;
        } else {
            arguments.IsValid = false;
        }
    }
</script>       
Rob
  • 869
  • 9
  • 11
-1

Non-javascript way . . aspx page:

 <form id="form1" runat="server">
<div>
    <asp:CheckBox ID="CheckBox1" runat="server" />
    <asp:CustomValidator ID="CustomValidator1"
        runat="server" ErrorMessage="CustomValidator" ControlToValidate="CheckBox1"></asp:CustomValidator>
</div>
</form>

Code Behind:

Protected Sub CustomValidator1_ServerValidate(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs) Handles CustomValidator1.ServerValidate
    If Not CheckBox1.Checked Then
        args.IsValid = False
    End If
End Sub

For any actions you might need (business Rules):

If Page.IsValid Then
   'do logic
End If 

Sorry for the VB code . . . you can convert it to C# if that is your pleasure. The company I am working for right now requires VB :(

andrewWinn
  • 1,786
  • 2
  • 14
  • 28