Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC3 unobtrusive validation group of inputs

I need to validate 3 or more input fields (required at lest one). For example I have Email, Fax, Phone.

I require at least ONE to be filled in. I need both server and client 'unobtrusive validation'. please help. I looked into "Compare" method and tried modifying it but no luck. please help. thanks

like image 690
ShaneKm Avatar asked Apr 28 '11 09:04

ShaneKm


People also ask

What is unobtrusive validation?

Unobtrusive Validation means without writing a lot of validation code, you can perform simple client-side validation by adding the suitable attributes and including the suitable script files. These unobtrusive validation libraries need to be added: jquery.validate.min.js.

How is unobtrusive validation implemented in asp net mvc?

Unobtrusive Validation allows us to take the already-existing validation attributes and use them client-side to make our user experience that much nicer. The Unobtrusive script files are included automatically with new MVC projects in Visual Studio, but if you don't have them you can get them from NuGet.

How do I turn off unobtrusive validation?

You can disable the unobtrusive validation from within the razor code via this Html Helper property: HtmlHelper. ClientValidationEnabled = false; That way you can have unobtrusive validation on and off for different forms according to this setting in their particular view/partial view.


1 Answers

You could write a custom attribute:

public class AtLeastOneRequiredAttribute : ValidationAttribute, IClientValidatable {     private readonly string[] _properties;     public AtLeastOneRequiredAttribute(params string[] properties)     {         _properties = properties;     }      protected override ValidationResult IsValid(object value, ValidationContext validationContext)     {         if (_properties == null || _properties.Length < 1)         {             return null;         }          foreach (var property in _properties)         {             var propertyInfo = validationContext.ObjectType.GetProperty(property);             if (propertyInfo == null)             {                 return new ValidationResult(string.Format("unknown property {0}", property));             }              var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);             if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string))             {                 return null;             }              if (propertyValue != null)             {                 return null;             }         }          return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));     }      public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)     {         var rule = new ModelClientValidationRule         {             ErrorMessage = ErrorMessage,             ValidationType = "atleastonerequired"         };         rule.ValidationParameters["properties"] = string.Join(",", _properties);          yield return rule;     } } 

which could be used to decorate one of your view model properties (the one you want to get highlighted if validation fails):

public class MyViewModel {     [AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")]     public string Email { get; set; }     public string Fax { get; set; }     public string Phone { get; set; } } 

and then a simple controller:

public class HomeController : Controller {     public ActionResult Index()     {         var model = new MyViewModel();         return View(model);     }      [HttpPost]     public ActionResult Index(MyViewModel model)     {         return View(model);     } } 

Rendering the following view which will take care of defining the custom client side validator adapter:

@model MyViewModel  <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> <script type="text/javascript">     jQuery.validator.unobtrusive.adapters.add(         'atleastonerequired', ['properties'], function (options) {             options.rules['atleastonerequired'] = options.params;             options.messages['atleastonerequired'] = options.message;         }     );      jQuery.validator.addMethod('atleastonerequired', function (value, element, params) {         var properties = params.properties.split(',');         var values = $.map(properties, function (property, index) {             var val = $('#' + property).val();             return val != '' ? val : null;         });         return values.length > 0;     }, ''); </script>  @using (Html.BeginForm()) {     @Html.ValidationSummary(false)      <div>         @Html.LabelFor(x => x.Email)         @Html.EditorFor(x => x.Email)     </div>      <div>         @Html.LabelFor(x => x.Fax)         @Html.EditorFor(x => x.Fax)     </div>      <div>         @Html.LabelFor(x => x.Phone)         @Html.EditorFor(x => x.Phone)     </div>      <input type="submit" value="OK" /> } 

Of course the custom adapter and validator rule should be externalized into a separate javascript file to avoid mixing script with markup.

like image 151
Darin Dimitrov Avatar answered Sep 25 '22 10:09

Darin Dimitrov