3
votes

I implement a custom validator to check if there is at least something checked:

public class AtLestOneRequiredAttribute : RequiredAttribute
    {
        public override bool IsValid(object value)
        {
            return (value != null);
        }
    }

    public class RequiredListValidator : DataAnnotationsModelValidator<AtLestOneRequiredAttribute>
    {
        private readonly string errorMessage;

        /// <summary>
        /// Initializes a new instance of the <see cref="EmailValidator"/> class.
        /// </summary>
        /// <param name="metadata">The metadata.</param>
        /// <param name="context">The context.</param>
        /// <param name="attribute">The attribute.</param>
        public RequiredListValidator(ModelMetadata metadata, ControllerContext context, AtLestOneRequiredAttribute attribute)
            : base(metadata, context, attribute)
        {
            this.errorMessage = attribute.ErrorMessage;
        }

        /// <summary>
        /// Retrieves a collection of client validation rules.
        /// </summary>
        /// <returns>A collection of client validation rules.</returns>
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = errorMessage,
                ValidationType = "atlestonerequired"
            };

            return new[] { rule };
        }        
    }

I also generate Unobtrusive Validation Attributes for that select (http://weblogs.asp.net/srkirkland/archive/2011/03/08/adding-unobtrusive-validation-to-mvccontrib-fluent-html.aspx)

Model:

[AtLestOneRequired(ErrorMessage="At least one selection required")]
        public IList<int> MyCheckBox{ get; set; }

View:

@this.CheckBoxList(x => x.MyCheckBox).Options(Model.MyCheckBoxes).IncludeUnobtrusiveValidationAttributes(Html)

In result i am getting this html with unobtrusive attributes in:

<div data-val="true" data-val-atlestonerequired="At least one selection required" id="MyCheckBox">
    <input id="MyCheckBox_0" name="MyCheckBox" type="checkbox" value="1"/>
    <label for="MyCheckBox_0" id="MyCheckBox_0_Label">A</label>
    <input id="MyCheckBox_1" name="MyCheckBox" type="checkbox" value="2"/>
    <label for="MyCheckBox_1" id="MyCheckBox_1_Label">B</label>
    <input id="MyCheckBox_2" name="MyCheckBox" type="checkbox" value="3"/>
    <label for="MyCheckBox_2" id="MyCheckBox_2_Label">C</label>
    <input id="MyCheckBox_3" name="MyCheckBox" type="checkbox" value="4"/>
    <label for="MyCheckBox_3" id="MyCheckBox_3_Label">D</label>
    ....
</div>

But my validaton does not work on client side, anything i need to do to make it work? I think may be i need to implement custom jQuery validaton method in that case if by default it is not working?

tried to add this:

jQuery.validator.addMethod("atlestonerequired", function (value, element) {
             return (value != null);
         });

         jQuery.validator.unobtrusive.adapters.addBool('atlestonerequired');

does not work.

2
I want to know the answer, on one? :(Maidot
I am also looking for solution for same!imdadhusen

2 Answers

1
votes

Spent some time on this issue. The reason that the client validation is not working is the way the unobtrusive validation selects the items that need to be validated. In particular the following line:

$(selector).find(":input[data-val=true]").each(function () {
  $jQval.unobtrusive.parseElement(this, true);
});

if you notice the ":input" which only applies to input|select|textarea|button

This means your "div[data-val=true]" will not be selected.

The way to get around this is to do this similar to the Required for a Radio button.

<div name="CheckBox" id="CheckBox">
  <input type="checkbox" data-val-cbrequired="Required" data-val="true" value="Default" name="CheckBox_0" id="CheckBox_0">
  <label for="CheckBox_0">Checkbox</label>
  <input type="checkbox" value="Yes" name="CheckBox_1" id="CheckBox_1">
  <label for="CheckBox_1">Yes</label>
  <input type="checkbox" value="No" name="CheckBox_2" id="CheckBox_2">
  <label for="CheckBox_2">No</label>
</div>

Then for the Jquery validation add:

$.validator.unobtrusive.adapters.addBool("cbrequired", "required");
0
votes

I dont know the accepted solution for this problem. But here is a work around for it.

I have the check box as:

<input name="TermsNConditions" type="checkbox" id="TermsNConditions" tabindex="12" />

The model has this property:

    [Required(ErrorMessage = "(Please accept the terms and conditions)")]
    [DefaultValue(0)]
    [RegularExpression(@"[^0]", ErrorMessage = "(Please accept the terms and conditions)")]
    public int AcceptTermsNConditions { get; set; }

and a hidden field for it

<%:Html.HiddenFor(model=>model.AcceptTermsNConditions) %>

I call a javascript change event on the check box as below:

$(function () {
        $("#TermsNConditions").live("change", function () {
            if ($("#TermsNConditions").attr('checked')) {
                $("#AcceptTermsNConditions").val(1);
            }
            else {
                $("#AcceptTermsNConditions").val(0);
            }
        });
        if ($("#AcceptTermsNConditions").val() == 1) {
            $("#TermsNConditions").attr('checked', true);
        }
    });

The above script sets the value for the hidden field and the model is validated against that hidden field.