Unobtrusive client-side validation for bool field not working in ASP.NET Core MVC

Viewed 1317

I found a very interesting problem in ASP.NET Core. I am using my bool field for a checkbox. I want to force the user to check the checkbox for the form to be submitted.

This bool field in my Model class is:

[Range(typeof(bool), "true", "true", ErrorMessage = "You must accept the Terms")]
public bool TermsAccepted { get; set; }

Notice I have applied [Range] validation attribute. And it works perfectly for the Server side validation.

My action method code is fairly simple:

[HttpPost]
public IActionResult Index(JobApplication jobApplication)
{
    if (ModelState.IsValid)
        return View("Accepted", jobApplication);
    else
        return View();
}

But the problem is happening when I apply client side validation

On my view i apply the 3 scripts:

@section scripts {
<script src="/lib/jquery/dist/jquery.min.js"></script>
<script src="/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="/lib/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.min.js">
</script>
}

The client side validation works totally opposite, it is giving error message when I check the checkbox. Why it is happening opposite?

The HTML code produced by the checkbox is:

<input type="checkbox" class="input-validation-error" data-val="true" data-val-range="You must accept the Terms" data-val-range-max="True" data-val-range-min="True" data-val-required="The TermsAccepted field is required." id="TermsAccepted" name="TermsAccepted" value="true" aria-describedby="TermsAccepted-error">

Please help?

2 Answers

I was having this problem, your code is ok with a few additions...

I updated to the latest versions of jquery.validate (1.19.1) and jquery.validation.unobtrusive (3.2.11), (using libman to manage these dependencies).

Also I added this javascript block to extend the functionality of the validator methods on that page.

 <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);
        }
      }
    </script>

All about jquery.validate.unobtrusive

Maybe too late. But I found one solution for validating check box 'Must Be True'. It will work on client side and server side as well It's possible to use same as with ConfirmPassword, but need to include to model one more hidden property bool with 'true' value. And to compare your check box with this property. Or just to use pure HTML if you have api call.

HTML for direct use

            <div class="input-group has-validation">
                <div class="form-check">
                    <input class="form-check-input" data-val="true" data-val-equalto="You have to agree with 'Terms amd Conditions' to register" data-val-equalto-other="AgreedWithTerms" data-val-required="You have to agree with 'Terms amd Conditions' to register" id="AgreeWithTerms" name="AgreeWithTerms" type="checkbox" value="true">
                    <input name="AgreedWithTerms" type="hidden" value="true">
                    <span class="field-validation-valid" data-valmsg-for="AgreeWithTerms" data-valmsg-replace="true"></span>
                    <label class="form-check-label" for="AgreeWithTerms">
                        <strong>Agree with</strong>
                        <a class="" href="/terms/" target="_blank">Terms and Conditions...</a>
                    </label>
                </div>
            </div>

In case of ASP.NET Core or Framework. Just include one hidden bool property to model "AgreedWithTerms" with value 'true' as follow:

C# Model

 [Required]
 [Compare("AgreedWithTerms", ErrorMessage = "You have to agree with 'Terms amd Conditions' to register")]
 public bool AgreeWithTerms { get; set; }

 [HiddenInput]
 public bool AgreedWithTerms { get; set; } = true;
Related