How to validate Date in ClientSide using FluentValidation?
14,431
Trick using Greater Then Or Equal To Validator. Works for me.
Global.asax - Application Start Event
FluentValidationModelValidatorProvider.Configure(x =>
{
x.Add(typeof(GreaterThanOrEqualValidator),
(metadata, Context, rule, validator) =>
new LessThanOrEqualToFluentValidationPropertyValidator
(
metadata, Context, rule, validator
)
);
});
Model
[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
[Display(Name = "Start date")]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",
ApplyFormatInEditMode = true)]
public DateTime StartDate { get; set; }
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",
ApplyFormatInEditMode = true)]
public DateTime DateToCompareAgainst { get; set; }
}
Rule
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.StartDate)
.GreaterThanOrEqualTo(x => x.DateToCompareAgainst)
.WithMessage("Invalid start date");
}
}
FluentValidationPropertyValidator
public class GreaterThenOrEqualTo : FluentValidationPropertyValidator
{
public GreaterThenOrEqualTo(ModelMetadata metadata,
ControllerContext controllerContext,
PropertyRule rule,
IPropertyValidator validator)
: base(metadata, controllerContext, rule, validator)
{
}
public override IEnumerable<ModelClientValidationRule>
GetClientValidationRules()
{
if (!this.ShouldGenerateClientSideRules())
{
yield break;
}
var validator = Validator as GreaterThanOrEqualValidator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(this.Rule.GetDisplayName())
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule{
ErrorMessage = errorMessage,
ValidationType = "greaterthanorequaldate"};
rule.ValidationParameters["other"] =
CompareAttribute.FormatPropertyForClientValidation(
validator.MemberToCompare.Name);
yield return rule;
}
}
Controller Action Method
public ActionResult Index()
{
var model = new MyViewModel
{
StartDate = DateTime.Now.AddDays(2),
DateToCompareAgainst = default(DateTime) //Default Date
};
return View(model);
}
[HttpPost]
public ActionResult Index(Practise.Areas.FluentVal.Models.MyViewModel p)
{
return View(p);
}
View
@using (Html.BeginForm("Index", "Person", FormMethod.Post,
new { id = "FormSubmit" }))
{
@Html.Hidden("DateToCompareAgainst", Model.DateToCompareAgainst);
@Html.LabelFor(x => x.StartDate)
@Html.EditorFor(x => x.StartDate)
@Html.ValidationMessageFor(x => x.StartDate)
<button type="submit">
OK</button>
}
Script
<script src="jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="jquery.validate.js" type="text/javascript"></script>
<script src="jquery.validate.unobtrusive.js" type="text/javascript"></script>
<script type="text/javascript">
(function ($) {
$.validator.unobtrusive.adapters.add('greaterthanorequaldate',
['other'], function (options) {
var getModelPrefix = function (fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
};
var appendModelPrefix = function (value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input[name=" + fullOtherName +
"]")[0];
options.rules['greaterthanorequaldate'] = element;
if (options.message != null) {
options.messages['greaterthanorequaldate'] = options.message;
}
});
$.validator.addMethod('greaterthanorequaldate',
function (value, element, params) {
var date = new Date(value);
var dateToCompareAgainst = new Date($(params).val());
if (isNaN(date.getTime()) || isNaN(dateToCompareAgainst.getTime())) {
return false;
}
return date >= dateToCompareAgainst;
});
})(jQuery);
</script>
Author by
SMC
Updated on August 11, 2022Comments
-
SMC over 1 year
Question
The below code is working fine
Server
side and not Client side. Why ?
When I submit the form, control goes toBeAValidDate
function to check the date is valid or not. Is there any way toValidate
the date without going to server usingFluent Validation
?Scripts
<script src="jquery-1.7.1.min.js" type="text/javascript"></script> <script src="jquery.validate.js" type="text/javascript"></script> <script src="jquery.validate.unobtrusive.js" type="text/javascript"></script>
Model
public class PersonValidator : AbstractValidator<Person> { public PersonValidator() { RuleFor(x => x.FromDate) .NotEmpty() .WithMessage("Date is required!") .Must(BeAValidDate) .WithMessage("Invalid Date"); } private bool BeAValidDate(String value) { DateTime date; return DateTime.TryParse(value, out date); } }
Controller
public class PersonController : Controller { public ActionResult Index() { return View(new Person { FromDate = DateTime.Now.AddDays(2).ToString()}); } [HttpPost] public ActionResult Index(Person p) { return View(p); } }
View
@using (Html.BeginForm("Index", "Person", FormMethod.Post)) { @Html.LabelFor(x => x.FromDate) @Html.EditorFor(x => x.FromDate) @Html.ValidationMessageFor(x => x.FromDate) <input type="submit" name="Submit" value="Submit" /> }
-
SMC over 10 yearsThis is called Data Annotation not Fluent Validation. Right ?
-
SMC over 10 yearsthanks for the answer. can you please share your experience for mvc3 ?
-
Francesco Abbruzzese over 10 yearsThe way to add client side validation to fluent validation is to implement a validator, so you can't use simply .Must, since it doesn't give way to add validation. It is enough that your validator implements the IClientValidatable interface. The fluent validation project explain how to create a custom validator here: fluentvalidation.codeplex.com/… In order to add client side validation your custom validator must implement the IClientValidatable.
-
Francesco Abbruzzese over 10 yearsThe way to impement IClientValidatable is exactly the same as with DataAnnotations. Unluckly for this reason it is not explained in the fluent validation web site. See here for a simple way to implement all client validation stuffs:stackoverflow.com/questions/5154231/… It is for DataAnnotations, bur as I said IT IS THE SAME. On the .Net side your validator must implement the same IClientValidatable class, and on the javascript side stuffs are exactly the same.
-
Francesco Abbruzzese over 10 yearsThat said the check for data validity SHOULD NOT be implemented with a rule applied to each DateTime, but should be applied automatically to all DateTime as Mvc4 do. The way to do this is to substitute the ClientDataTypeModelValidatorProvider of Mvc 3 that signals just ill formatted numbers, with one that validates also dates (like the one of Mvc 4). I have the code that solve the problem, but is not so self contained to be inserted here, if you are interested I can provide you that code.
-
Francesco Abbruzzese over 10 yearsSample code of what? A ClientDataTypeModelValidatorProvider that is able to signall automatically all hill formatted dates that is what you need in your example, or of how to Implement the IClientValidatable interfaces + associated javascript stuff?
-
SMC over 10 yearsYes. Need to correct my code so that it can start to work on client side to check valid date.
-
MsBao about 8 yearsAll that to compare a number.