Question
The below code is working fine Server
side and not Client side. Why ?
When I submit the form, control goes to BeAValidDate
function to check the date is valid or not. Is there any way to Validate
the date without going to server using Fluent 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" />
}
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>