Single ClientValidationFunction for Multiple Dynamic CustomValidator and CheckBox

By | November 17, 2010

I have been using CheckBoxes and CustomValidators for quite sometime now but never did I know that I will be presented with an issue that I never encountered before and that issue is regarding is dynamic CheckBoxes and dynamic CustomValidators.  To give you an idea on what I am talking about, if you had developed a website that has that “Agree to Terms and Conditions” required before continuing then your guess is a bit near the only difference is making the items dynamic where these questions are pulled from the database, that database table also defines whether the tick is required or not.

For the first scenario (non dynamic) its easy as you only need these controls


<asp:CheckBox ID="CheckBox1" runat="server" />
<asp:CustomValidator ID="CustomValidator1" runat="server" ErrorMessage="CustomValidator"
ClientValidationFunction="ValidateCheckbox"></asp:CustomValidator>

and this javascript to be consumed by the CustomValidator

<script language="JavaScript" type="text/javascript">
function ValidateCheckbox(source, args) {
    args.IsValid = args.IsValid = document.getElementById('<%= CheckBox1.ClientID %>').checked;
}
</script> 

But what if you have 50 checkboxes will you create one script for each one of them? Wouldn’t it be nice to just pass a parameter to your javascipt? By default you cannot do that as the javascript that the CustomValidator uses only 2 parameters which is the source and args.  But don’t worry we can use RegisterExpandoAttribute Method to extend an objects attribute.

So what does that method do? The answer is simple it registers a name/value pair as a custom attribute of the specified control.   Having that in mind we use it in the CustomValidator and extend its attributes to have the ClientID of the checkbox you want to validate. So for clarity refer to the example below.

So lets say we have the following controls that is dynamically driven by the GridVeiw

<asp:GridView ID="myGridView" runat="server" AutoGenerateColumns="False" OnRowDataBound="myGridView_RowDataBound">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:Label ID="lblQuestionItem" runat="server" Text='<%# Bind("QuestionItem") %>'
                    CssClass="Normal"></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:HiddenField ID="hdnIsRequired" runat="server" Value='<%# Bind("IsRequired") %>' />
                <asp:CheckBox ID="chkAnswer" runat="server" CssClass='<%# Bind("ControlClass") %>' />
                <asp:CustomValidator ID="ctmCHKAnswer" ClientValidationFunction="ValidateCurrentCheckbox"
                    runat="server" ErrorMessage="*"></asp:CustomValidator>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Now from the sample above we defined a CustomValidator and that’s the object that we will extend the attributes to contain the chkAnswer‘s client ID, to do that here is the code behind, also remember that you need to do that on a per row basis as well thats why it is in myGridView_RowDataBound, and here is how to achieve it.

protected void myGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        HiddenField hdnIsRequired = (HiddenField)e.Row.FindControl("hdnIsRequired");
        CheckBox chkAnswer = (CheckBox)e.Row.FindControl("chkAnswer");
        CustomValidator ctmCHKAnswer = (CustomValidator)e.Row.FindControl("ctmCHKAnswer");

        Page.ClientScript.RegisterExpandoAttribute(ctmCHKAnswer.ClientID, "ClientID", chkAnswer.ClientID, false);
        ctmCHKAnswer.Enabled = bool.Parse(hdnIsRequired.Value);
    }
}

If you noticed we extended ctmCHKAnswer with the “ClientID” attribute that comes from chkAnswer.ClientID.  So when you fire the JavaScript you can then now use the source parameter and use source.ClientID to get the checkbox client ID you need.

<script language="JavaScript" type="text/javascript">
function ValidateCurrentCheckbox(source, args) {
    var checkbox = document.getElementById(source.ClientID)
    args.IsValid = checkbox.checked;
}
</script>


Leave a Reply