Perform client side validation for custom attribute
Here's how to proceed:
Start by defining the custom validation attribute:
public class FutureDateAttribute : ValidationAttribute, IClientValidatable{ public override bool IsValid(object value) { if (value == null || (DateTime)value < DateTime.Now) return false; return true; } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { yield return new ModelClientValidationRule { ErrorMessage = this.ErrorMessage, ValidationType = "futuredate" }; }}
Notice how it implements IClientValidatable. Next we write our model:
public class MyViewModel{ [FutureDate(ErrorMessage = "Should be in the future")] public DateTime Date { get; set; }}
Then a controller:
public class HomeController : Controller{ public ActionResult Index() { return View(new MyViewModel { // intentionally put in the past Date = DateTime.Now.AddDays(-1) }); } [HttpPost] public ActionResult Index(MyViewModel model) { return View(model); }}
and finally a view:
@using (Html.BeginForm()){ @Html.LabelFor(x => x.Date) @Html.TextBoxFor(x => x.Date) @Html.ValidationMessageFor(x => x.Date) <input type="submit" value="OK" />}
The last part for the magic to happen is to define the custom adapter:
<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"> // we add a custom jquery validation method jQuery.validator.addMethod('greaterThan', function (value, element, params) { if (!/Invalid|NaN/.test(new Date(value))) { return new Date(value) > new Date($(params).val()); } return isNaN(value) && isNaN($(params).val()) || (parseFloat(value) > parseFloat($(params).val())); }, ''); // and an unobtrusive adapter jQuery.validator.unobtrusive.adapters.add('futuredate', { }, function (options) { options.rules['greaterThan'] = true; options.messages['greaterThan'] = options.message; });</script>
It took a little while since your question was asked, but if you still like metadata, and you're still open for simplified alternatives, you can solve your problem using following annotations:
[Required][AssertThat("Date > Now()")]public DateTime? Date { get; set; }
It works for both - server and client, out of the box. For further details take a look at ExpressiveAnnotations library.