Home Required Checkbox validation works in reverse for Html.CheckBoxFor
Reply: 1

Required Checkbox validation works in reverse for Html.CheckBoxFor

Pradvaar cruz
1#
Pradvaar cruz Published in 2017-09-13 02:37:45Z

This question already has an answer here:

  • MVC Model require true 15 answers

I have a checkbox validation before i submit the page. But it works in reverse. It's displaying error message when i check the box instead of opposite. I don't know where im doing wrong.

My ViewModel

[Display(Name = "Terms and Conditions")]
[Range(typeof(bool), "true", "true", ErrorMessage = "Please accept Terms & Conditions")]
public bool IsTermsAccepted { get; set; }

My View

<div class="row col-lg-offset-2 top-buffer">
                @Html.CheckBoxFor(model => model.IsTermsAccepted)
                @Html.LabelFor(model => model.IsTermsAccepted)
            <br>@Html.ValidationMessageFor(model => model.IsTermsAccepted)
        </div>

Thank you for your time!

Edit1: I followed exactly like here

Edit2: I was able to resolve this by adding a simple script (as shown in the above mentioned link)

<script>
// extend range validator method to treat checkboxes differently
var defaultRangeValidator = $.validator.methods.range;
$.validator.methods.range = function(value, element, param) {
    if(element.type === 'checkbox') {
        // if it's a checkbox return true if it is checked
        return element.checked;
    } else {
        // otherwise run the default validation function
        return defaultRangeValidator.call(this, value, element, param);
    }
}

Dai
2#
Dai Reply to 2017-09-13 02:50:18Z

You need to understand how CheckBoxFor works in ASP.NET MVC - and how checkboxes work in HTML (see my answer to this question: https://stackoverflow.com/a/11424091/159145 )

  • HTML checkboxes do not post their value in the POST request body if they are not checked.
  • So in order to tell the difference between "checkbox-not-checked" and "checkbox-excluded" you need to include an explicit "false" value as <input type="hidden" /> with the same name="" property value as the checkbox input's.
  • ASP.NET MVC does this for you: Html.CheckBoxFor() renders both an <input type="checkbox" value="true" /> and an <input type="hidden" value="false" />
    • If you look at the rendered HTML of your page, you'll see them both.

so when you submit a checked checkbox, your browser is actually sending two values: true and false. It's the "false" value that causes your Range validator to fail, even though it also sent the true value.

However, the RangeValidatorAttribute is not smart enough to handle this specific case for boolean ViewModel properties set using CheckBoxFor.

As far as I know, there is no built-in DataAnnotation attribute that handles this case - you will need to implement it yourself in your Controller Action, like so:

[HttpPost]
public IHttpActionResult Foo(FooViewModel model) {

    if( !model.IsTermsAccepted ) {

        this.ModelState.AddModelError( nameof(model.IsTermsAccepted), "you must accept the terms." );
        return this.View( model );
    }

}

...or you could try to implement a new validation attribute yourself, it would need to do something like this.

Note it derives from Required attribute, because you need to ensure both that the property has a value in the request body (i.e. that the checkbox was included in the response, with the hidden input) and that the true value is present.

[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
class CheckboxIsCheckedAttribute : RequiredAttribute {

    public override bool IsValid(Object value) {

        Boolean isRequiredValid = base.IsValid( value );
        if( !isRequiredValid ) return false;

        return (value as Boolean) == true;
    }
}
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.527943 second(s) , Gzip On .

© 2016 Powered by cudou.com design MATCHINFO