📜 ⬆️ ⬇️

Unobtrusive Validation in ASP.NET MVC3

Not long ago, I started developing ASP.NET MVC websites and in one of my projects I had a need for a non-standard validator that would check if a form element is required to be filled depending on the value of another element. That is what I want to tell.

The site was developed on automotive topics. The need for a validator appeared on the registration form. The user can register as an individual and as a car dealer. If the user wants to register as a car dealer, then he needs to fill in a few additional required fields. Of course, it was possible to do the registration in several stages, but I wanted the entire registration process to take place in one step.


Server part

')
To create our own validator, we need to inherit from the ValidationAttribute class.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)] public sealed class RequiredIfAttribute : ValidationAttribute, IClientValidatable { //,    . private const string _defaultErrorMessage = "{0} is required"; //  private string _targetPropertyName; //   private bool _targetPropertyCondition; public RequiredIfAttribute(string targetPropertyName, bool targetPropertyCondition) : base(_defaultErrorMessage) { this._targetPropertyName = targetPropertyName; this._targetPropertyCondition = targetPropertyCondition; } public override string FormatErrorMessage(string name) { return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, name, _targetPropertyName, _targetPropertyCondition); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { bool result = false; bool propertyRequired = false; //       . //   var targetProperty = validationContext.ObjectType.GetProperty(_targetPropertyName); //    var targetPropertyValue = (bool)targetProperty.GetValue(validationContext.ObjectInstance, null); //     ,      . if (targetPropertyValue == _targetPropertyCondition) { propertyRequired = true; } if (propertyRequired) { //    if (value == null) { var message = FormatErrorMessage(validationContext.DisplayName); return new ValidationResult(message); } } return null; } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule(); rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()); rule.ValidationType = "requiredif"; rule.ValidationParameters.Add("targetpropertyname", this._targetPropertyName); rule.ValidationParameters.Add("targetpropertyvalue", this._targetPropertyCondition.ToString().ToLower()); yield return rule; } } 


Define an attribute for the error message that will be issued to the user in _defaultErrorMessage, and also define two fields _targetPropertyName and _targetPropertyCondition, which will store the name of the field in the model, depending on which will be checked whether the current field is filled (for which this attribute is specified) and the value of this field, respectively.

In order to implement client validation, it is necessary to inherit the IClientValidatable interface. In the GetClientValidationRules method, we create a new rule for which we specify an error message, a validator type, as well as the parameters of our validator. Subsequently, all this will be added to the markup form.



Client part


This completes the server part. Let us turn to the client part. In order for our validator to work on the client side, we need to create our own validation function and our adapter.

 $(function () { $.validator.addMethod("requiredif", function (value, element, param) { if ($(param.propertyname).is(':checked').toString() == param.propertyvalue) { if (!this.depend(param, element)) return "dependency-mismatch"; switch (element.nodeName.toLowerCase()) { case 'select': var val = $(element).val(); return val && val.length > 0; case 'input': if (this.checkable(element)) return this.getLength(value, element) > 0; default: return $.trim(value).length > 0; } } return true; }); $.validator.unobtrusive.adapters.add("requiredif", ["targetpropertyname", "targetpropertyvalue"], function (options) { if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { options.rules["requiredif"] = { propertyname: "#" + options.params.targetpropertyname, propertyvalue: options.params.targetpropertyvalue }; options.messages["requiredif"] = options.message; } }); } (jQuery)); 


Using:


In order to use, you must specify the RequiredIf attribute in the model for the corresponding fields:

 public class RegisterModel { [Required] [Display(Name = "First name")] public string FirstName { get; set; } [Required] [Display(Name = "Last name")] public string LastName { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "Email address")] [RegularExpression("^([A-Za-z0-9_\\-\\.])+\\@([A-Za-z0-9_\\-\\.])+\\.([A-Za-z]{2,4})$", ErrorMessage = "Not a valid email.")] public string Email { get; set; } [Display(Name = "Dealer")] public bool IsDealer { get; set; } [RequiredIf("IsDealer", true)] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 3)] [Display(Name = "Dealer name")] public string Name { get; set; } } 


And also add our script to the page:
  <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.requiredif.js")" type="text/javascript"></script> 


As a result, we got a fairly easy-to-use validator that works on both the server and client side:



PS: By default, unobtrusive validation is disabled in ASP.NET MVC3. You can enable it in two ways. First, using the Web.config file:

  <appSettings> <add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> </appSettings> 


You can also specify in the code:

 HtmlHelper.ClientValidationEnabled = true; HtmlHelper.UnobtrusiveJavaScriptEnabled = true; 


and you also need to add a couple of JavaScript files in the View:

 <script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 

Source: https://habr.com/ru/post/129398/


All Articles