Question

I have an MVC4 registration form that employs two custom remote validators. The first validator checks for email uniqueness, and works properly. The second checks number of uses for a voucher code. It correctly displays a message after entering a voucher code, but it fails to honor the custom remote validation at the point of submission.

In other words, you can enter a voucher code and see the "Cannot use voucher..." message from the remote validator. But you can still submit the form.

This is the abbreviated markup for the form, with just the relevant fields and the submit button. The full form is much larger. The email fields, which use custom validation successfully, are retained in this example for comparison. You can see the RegistrationVoucherCode field and validator near the end of the form.

@using (Html.BeginForm("Index", "Registration", FormMethod.Post))
  {
     <div class="row">
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
           <div class="form_label">@Html.LabelFor(m => m.EmailAddress)</div>
           <div class="form_field">@Html.TextBoxFor(m => m.EmailAddress)</div>
           <div class="form_validator">@Html.ValidationMessageFor(m => m.EmailAddress)</div>
        </div>
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
           <div class="form_label">Confirm Email</div>
           <div class="form_field">@Html.TextBoxFor(m => m.ConfirmEmail)</div>
           <div class="form_validator">@Html.ValidationMessageFor(m => m.ConfirmEmail)</div>
        </div>
     </div>
     <div class="row">
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
           <div class="form_label">@Html.LabelFor(m => m.RegistrationVoucherCode)</div>
           @{ 
              string displayVoucherCode = Model.RegistrationVoucherCode.ToString();
              if (Model.RegistrationVoucherCode == 0)
              {
                 displayVoucherCode = string.Empty;
              }
           }
           <div class="form_field">@Html.TextBoxFor(m => m.RegistrationVoucherCode, new { Value = displayVoucherCode, maxlength = 7 })</div>
           <div class="form_validator">@Html.ValidationMessageFor(m => m.RegistrationVoucherCode)</div>
        </div>
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
        </div>
     </div>
     <div class="row">
        <div class="col-xs-12">
           <input type="submit" id="submitForm" value="Next" class="standard_button right_button" />
        </div>
     </div>
  }

This is related code from my ProfileModel. The full model is much larger, so only relevant code is presented here. At the end of this you can see RegistrationVoucherCode.

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace SW.CEA.WebSite.Models.Registration
{
public class ProfileModel
{
  public ProfileModel()
  {
  }

  public Profile Profile { get; set; }


  [Required(ErrorMessage = "Confirm Email is required.")]
  [Display(Name = "Confirm Email")]
  [StringLength(128)]
  [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Confirm Email Address is Not Valid")]
  [System.Web.Mvc.Compare("EmailAddress", ErrorMessage = "Email addresses do not match..")]
  public string ConfirmEmail
  {
     get
     {
        return Profile.ConfirmEmail;
     }
     set
     {
        Profile.ConfirmEmail = value;
     }
  }

  [Required(ErrorMessage = "Email Address is required.")]
  [Display(Name = "Email")]
  [StringLength(128)]
  [Remote("ValidateEmailUniqueness", "Registration")]
  [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Email Address is Not Valid")]
  public string EmailAddress
  {
     get
     {
        return Profile.EmailAddress;
     }
     set
     {
        Profile.EmailAddress = value;
     }
  }

  [Required(ErrorMessage = "Order Code is required.")]
  [Display(Name = "Order Code")]
  [Remote("ValidateVoucherCode", "Registration")]
  public int RegistrationVoucherCode
  {
     get
     {
        return Profile.RegistrationVoucherCode;
     }
     set
     {
        Profile.RegistrationVoucherCode = value;
     }
  }

}
}

And these are custom validators from my RegistrationController. Again, email address validators appear here for comparison. My problem is with enforcing the ValidateVoucherCode custom validator at the point of form submission.

  private bool IsEmailUnique(string EmailAddress)
  {
     var profile = ProfileRepository.GetProfile(EmailAddress);
     return (profile == null);
  }

  [HttpGet]
  public JsonResult ValidateEmailUniqueness(string EmailAddress)
  {
     if (!IsEmailUnique(EmailAddress))
     {
        return Json("Error, email address is already registered, please sign in.", JsonRequestBehavior.AllowGet);
     }
     return Json(true, JsonRequestBehavior.AllowGet);
  }

  [HttpGet]
  public JsonResult ValidateVoucherCode(int RegistrationVoucherCode)
  {
     var voucher = VoucherRepository.GetVoucherWithProfiles(RegistrationVoucherCode);
     if (voucher == null)
     {
        return Json("Invalid Order Code", JsonRequestBehavior.AllowGet);
     }
     if (voucher.Profiles.Count >= Settings.Default.MaxVoucherUses)
     {
        return Json("Cannot user voucher, will exceed maximum number of voucher uses.", JsonRequestBehavior.AllowGet);
     }
     return Json(true, JsonRequestBehavior.AllowGet);
  }

The message, "Cannot user voucher, will exceed maximum number of voucher uses," will successfully appear on the client in this ValidationMessageFor when an overused validation code is entered. This again is from the form.

@Html.TextBoxFor(m => m.RegistrationVoucherCode, new { Value = displayVoucherCode, maxlength = 7 })
@Html.ValidationMessageFor(m => m.RegistrationVoucherCode)

Upon tabbing off the form field, debugger shows this remote validator being hit.

[HttpGet]
public JsonResult ValidateVoucherCode(int RegistrationVoucherCode)

So the ValidateVoucherCode custom validator is doing part of it's job. It's showing the "Cannot use voucher..." message when I tab off the field. But it doesn't prevent the form from being submitted. By contrast, the unique email address validator on the same form will prevent form submission. I need the RegistrationVoucherCode validator to operate in the same manner. Thanks for your help.

Was it helpful?

Solution

The solution was to replace jquery-2.1.0.min.js with https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js.

The scripts that my form presently uses are:

https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js
jquery.validate.min.js
jquery.validate.unobtrusive.min.js
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top