user147215
user147215

Reputation:

asp:CustomValidator / OnServerValidate

I have a CheckBoxList that I am trying to validate that at least one of the checkboxes is checked.

Markup:

<asp:CustomValidator ID="RequiredFieldValidator8" ValidationGroup="EditArticle"
    runat="server" ErrorMessage="At least one Category is required."
    OnServerValidate="topic_ServerValidate" />
<asp:CheckBoxList id="checkboxlistCategories" runat="server"></asp:CheckBoxList>

Code-behind:

protected void topic_ServerValidate(object source, ServerValidateEventArgs args)
{
    int i = 0;
    foreach (ListItem item in checkboxlistCategories.Items)
    {
        if (item.Selected == true)
            i = i + 1;
    }
    if (i == 0)
        args.IsValid = false;
    else
        args.IsValid = true;
}

If I add ControlToValidate="checkboxlistCategories" in the CustomValidator control, it blows up! The exception I get is:

System.Web.HttpException: Control 'checkboxlistCategories' referenced by the ControlToValidate property of 'RequiredFieldValidator8'

Am I missing something?

Upvotes: 3

Views: 8257

Answers (5)

Nariman
Nariman

Reputation: 6426

Here's a cleaner jQuery implementation that allows one ClientValidationFunction for any number of CheckBoxList controls on a page:

function ValidateCheckBoxList(sender, args) {
 args.IsValid = false;

 $("#" + sender.id).parent().find("table[id$="+sender.ControlId+"]").find(":checkbox").each(function () {
     if ($(this).attr("checked")) {
  args.IsValid = true;
  return;
     }
 });
}

Here's the markup:

<asp:CheckBoxList runat="server"
    Id="cblOptions" 
    DataTextField="Text" 
    DataValueField="Id" />

<xx:CustomValidator Display="Dynamic" 
        runat="server" 
        ID="cblOptionsValidator"
        ControlId="cblOptions"
        ClientValidationFunction="ValidateCheckBoxList" 
        ErrorMessage="One selection required." />

And finally, the custom validator that allows the client function to retrieve the target control by ID:

public class CustomValidator : System.Web.UI.WebControls.CustomValidator
{
 public string ControlId { get; set; }

 protected override void OnLoad(EventArgs e)
 {
     if (Enabled)
         Page.ClientScript.RegisterExpandoAttribute(ClientID, "ControlId", ControlId);

     base.OnLoad(e);
 }
}

Upvotes: 1

EightyOne Unite
EightyOne Unite

Reputation: 11795

As Mehdi mentioned, 4 Guys covered this in the article he links to in his answer.

For brevity, here's the code listing-

public class CheckBoxListRequiredFieldValidator : BaseValidator
{
    private ListControl _listctrl;

    public CheckBoxListRequiredFieldValidator()
    {
        base.EnableClientScript = false;
    }

    protected override bool ControlPropertiesValid()
    {
        Control ctrl = FindControl(ControlToValidate);

        if (ctrl != null)
        {
            _listctrl = (ListControl)ctrl;
            return (_listctrl != null);
        }
        else
            return false;  
    }

    protected override bool EvaluateIsValid()
    {
        return _listctrl.SelectedIndex != -1;
    }
}

Pop this badger into you user controls library and away you go.

HTH.

Upvotes: 0

m3kh
m3kh

Reputation: 7941

Maybe I'm missing something. But CheckBoxList control does not have the ValidationPropertyAttribute. Thus you can't use it as ControlToValidate property. Try this:

CheckBoxList.cs

[ValidationProperty("SelectedIndex")]
public class CheckBoxList : System.Web.UI.WebControls.CheckBoxList
{
}

Web.Config

<tagMapping>
  <add tagType="System.Web.UI.WebControls.CheckBoxList, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" mappedTagType="Namespace.CheckBoxList, Assembly"/>
</tagMapping>

Anyway Scott Mitchell has written a great article about it here.

Upvotes: 0

Eric
Eric

Reputation: 8078

Just a suggestion, but you could use radio buttons instead and define a group name. This would eliminate the need for the validation b/c only one radio button can be checked within the group.

Upvotes: 0

J&#248;rn Schou-Rode
J&#248;rn Schou-Rode

Reputation: 38336

Considering that your server side validation method topic_ServerValidate is tied specificly to the checkboxlistCategories field, you do not need to set the ControlToValidate property.

The reason that it "blows up" when you add the ControlToValidate property, is the type of the control you are referencing - a CheckBoxList. When assigning a ControlToValidate to any kind of validator, that validator will automatically do a "non empty" check on the referenced control before performing the actual validation logic. If the field is empty, no validation will be done (i.e. validation success). That is, of course, unless you set ValidateWhenEmpty = true. Apparently, the validators do not know how to check if a CheckBoxList is empty, and instead they throw an exception.

In your specific case, where the CustomValidator really just serves as non-empty check, you definatly want validator to occur even when the referenced control is left "empty". As stated in the first paragraph of my answer, the simplest way to achieve this is to remove the offending - and unnecessary - property.

Upvotes: 0

Related Questions