MVC 3 Custom ValidationAttribute for CheckBox For two-shot shooting on the client side

I am going to lay out the code to explain the whole situation, and then describe the problem:

In my view model, I have a boolean property to track if the user accepted the conditions:

[MustBeTrue(ErrorMessageResourceType = typeof(ErrorMessages), ErrorMessageResourceName = "MustAccept")] public bool HasAuthorizedBanking { get; set; } 

As you can see, I created a special validation attribute to process this MustBeTrue name to handle the flag, since [Required] does not currently work for the -side client check flags in MVC 3

 public class MustBeTrueAttribute : ValidationAttribute, IClientValidatable { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if ((bool)value) return ValidationResult.Success; return new ValidationResult(String.Format(ErrorMessageString,validationContext.DisplayName)); } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "truerequired" }; yield return rule; } } 

Then I add CheckBoxFor with ValidationMessage in my view:

 @Html.CheckBoxFor(model => model.HasAuthorizedBanking) @Html.ValidationMessageFor(model => model.HasAuthorizedBanking, "", new { @class = "validationtext" }) 

To implement this client side, I created a jQuery validation method and added an unobtrusive adapter:

 // Checkbox Validation jQuery.validator.addMethod("checkrequired", function (value, element) { var checked = false; checked = $(element).is(':checked'); return checked; }, ''); jQuery.validator.unobtrusive.adapters.addBool("truerequired", "checkrequired"); 

In my opinion, all the steps of the registration process are on the same page, the elements are hidden and shown through jQuery and verified using jQuery validation. When the "Next" button is clicked, each input element on the page is launched to verify:

  var validator = $("#WizardForm").validate(); // obtain validator var anyError = false; $step.find("input").each(function () { if (!validator.element(this)) { // validate every input element inside this step anyError = true; } }); if (anyError) return false; 

Notes:

  • In my model there is only one property with the MustBeTrue attribute, and on the whole page there is only one CheckBoxFor and the corresponding ValidationMessageFor.
  • To keep track of when this method is being called, I simply put a warning (checked); inside the jQuery "checkrequired" validation method.

Problem: If the checkbox is checked or unchecked, the "checkrequired" method runs once. However, when the "Next" button is clicked, and we go to check all the input elements, it launches twice, regardless of whether the check box is selected. Interestingly, if it is checked, the first check returns true, and the second returns false (this second false return is my main problem - the page will not be checked, and this will not allow you to go to the next step). In addition, when it is installed, and Next is clicked, the ValidationMessageFor message disappears as if it were valid.

Edit: I have another custom attribute for checking Age in the jQuery DatePicker text box, and although it is implemented in the same way - it only works once under the same conditions.

+7
source share
1 answer

It turns out the problem is that the second input element with the same name as the checkbox is generated by Html.CheckBoxFor, as described here: http://forums.asp.net/t/1314753.aspx

 <input data-val="true" data-val-required="The HasAuthorizedBanking field is required." data-val-truerequired="You must accept to continue." id="bankingtermscheckbox" name="HasAuthorizedBanking" type="checkbox" value="true" /> <input name="HasAuthorizedBanking" type="hidden" value="false" /> 

The fix was to change the jQuery selector to look only at input elements whose type is not hidden:

 $step.find(':input:not(:hidden)').each(function () { // Select all input elements except those that are hidden if (!validator.element(this)) { // validate every input element inside this step anyError = true; } }); if (anyError) return false; // exit if any error found 
+4
source

All Articles