JQuery Datetimepicker date selected does not match date today - asp.net-mvc

I am working on a scheduling project in MVC 5. I want to check the Date Selected against current Date. If they match, display the scheduled appointment for Today' date only in a view. Currently, the appointments do not display when I add "appointment.AppointmentDate == DateTime.Now". Instead the View duplicates "No Appointments Today'.
I have researched through StackOverFlow and other sites to try and figure out with no luck. One attempt was adding ".data('date') in the Create view: " $('#datetimepicker1.data('date'), #datetimepicker2').datetimepicker " to set the type as Date but was unsuccessful. I am a beginner and hope someone may be able to help me in the right direction. Thanks.
My code is below:
MODEL:
public enum AppointmentTime
{
_1pm_to_2pm, ApplicationDbContext _dbContext = new ApplicationDbContext();
public ActionResult Create(int id)
{
Property property = _dbContext.Properties.SingleOrDefault(b => b.PropertyID == id);
ViewBag.propertyName = property.PropertyName;
Consultation consultation = new Consultation();
consultation.PropertyID = id;
return View(consultation);
}
[HttpPost]
public ActionResult Create(Consultation consultation)
{
try
{
if (ModelState.IsValid)
{
Property property = _dbContext.Properties.SingleOrDefault(b => b.PropertyID == consultation.PropertyID);
property.Consultations.Add(consultation);
_dbContext.SaveChanges();
return RedirectToAction("Details", "Property", new { id = property.PropertyID });
}
return View();
}
catch
{
return View("Error");
}
}
_2pm_to_3pm,
_3pm_to_4pm,
_4pm_to_5pm,
_5pm_to_6pm
}
public class Consultation
{
[Key]
public int AppointmentID { get; set; }
[ForeignKey("Property")]
public int PropertyID { get; set; }
[Display(Name = "Enter your name")]
public string AppointmentName { get; set; }
[Required]
[Display(Name = "Email")]
public string AppointmentEmail { get; set; }
[Display(Name = "Select Date")]
[UIHint("AppointmentDate")]
[Required]
public DateTime AppointmentDate { get; set; }
public AppointmentTime AppointmentTime { get; set; }
public virtual Property Property { get; set; }
}
CONTROLLOR:
[Authorize(Roles = "Admin")]
public ActionResult AdminAppointmentView(Consultation consultaion)
{
var appointments = _dbContext.Consultations.ToList();
return View(appointments);
}
CREATE VIEW
#model OpenProperties.Models.Consultation
#{
ViewBag.Title = "Create Appointment";
}
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css"
rel="stylesheet">
<link rel="stylesheet" type="text/css" media="screen"
href="http://tarruda.github.com/bootstrap-datetimepicker/assets/css/bootstrap-datetimepicker.min.css">
#using (Html.BeginForm(new { enctype = "multipart/form-data", id = "form1" }))
{
#Html.ValidationSummary(true)
<div>
#Html.HiddenFor(model => model.PropertyID)
<br />
<div class="form-group">
#Html.LabelFor(m => m.AppointmentName)
#Html.TextBoxFor(m => m.AppointmentName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.AppointmentEmail)
#Html.TextBoxFor(m => m.AppointmentEmail, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(model => model.AppointmentTime, new { #class = "control-label col-md-2" })
#Html.EnumDropDownListFor(model => model.AppointmentTime)
#Html.ValidationMessageFor(model => model.AppointmentTime)
</div>
<div id="datetimepicker1" class="input-append date">
#Html.TextBoxFor(m => m.AppointmentDate, "{0:dd/MM/yyyy HH}",
new { placeholder = "App Date", #class = "dtPicket" })
<span class="add-on">
<i data-time-icon="icon-time"
data-date-icon="icon-calendar"></i>
</span>
</div>
<br />
<br />
<input type="submit" value="Submit" />
</div>
<script type="text/javascript"
src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<script type="text/javascript"
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js">
</script>
<script type="text/javascript"
src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.min.js">
</script>
<script type="text/javascript"
src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.pt-BR.js">
</script>
<script type="text/javascript">
$('#datetimepicker1, #datetimepicker2').datetimepicker({
format: 'dd/MM/yyyy'
});
</script>
}
AdminAppointmentView VIEW:
#model IEnumerable<OpenProperties.Models.Consultation>
<h2>Todays Appointments</h2>
#foreach (var appointment in Model)
{
if (appointment.AppointmentDate == DateTime.Now)
{
<li>
<ul>#appointment.AppointmentID</ul>
<ul>#appointment.AppointmentDate</ul>
<ul>#appointment.AppointmentEmail</ul>
<ul>#appointment.AppointmentName</ul>
<ul>For Property ID: #appointment.PropertyID</ul>
</li>
}
else
{
<ul> No Appointments Today </ul>
}
}

Just at first Glance.
if (appointment.AppointmentDate == DateTime.Now)
(
}
Is the date Format is same for appointment.AppointmentDate and DateTime.Now??.
If not just add Tostring Method to these date.
ex.
DateTime.Now.ToString("MMMM dd, yyyy")
2) You might check the // Difference in days, hours, and minutes. between the date as well. Instead of comparing
DateTime oldDate = new DateTime(2002,7,15);
DateTime newDate = DateTime.Now;
// Difference in days, hours, and minutes.
TimeSpan ts = newDate - oldDate;
// Difference in days.
int differenceInDays = ts.Days;
3) You can format date in datetime Picker as follows.
$('#datepicker').datetimepicker({
dateFormat: "yy-mm-dd",
timeFormat: "hh:mm:ss"
});
4) Also could you please put Script and datepicker code before the html
<script type="text/javascript"
src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<script type="text/javascript"
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js">
</script>
<script type="text/javascript"
src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.min.js">
</script>
<script type="text/javascript"
src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.pt-BR.js">
</script>
<script type="text/javascript">
$('#datetimepicker1, #datetimepicker2').datetimepicker({
format: 'dd/MM/yyyy'
});
</script>

Related

Chosen plugin validation asp.net mvc

I am using chosen js plugin for multiselect drop down in my asp.net mvc core application. I want to validate if the user selects atleast one value in that multiselect listbox.
I actually want red bordered listbox with Required on next to listbox, however its not working. I am using the same code for single selected dropdown list and its working (but its with out chosen plugin). I couldn't find any documentation in the chosen github as well.
cshtml code
#Html.ListBoxFor(model => model.SelectedLanguages, new MultiSelectList(Model.Languages, "Value", "Text"), htmlAttributes: new { id = "LanguageDropDown", multiple = "multiple", #class = "listbox-text" })
#Html.ValidationMessageFor(model => model.Languages)
Model
[Display(Name = "Language(s)")]
[Required(ErrorMessage = "Required")]
public string Language { get; set; }
public IEnumerable<SelectListItem> Languages { get; set; }
public string[] SelectedLanguages { get; set; }
Controller (for loading the data to the List box)
public IEnumerable<SelectListItem> GetLanguages()
{
using (var _dbcontext = new DataContext(DataContext.opsBuild.dbOptions))
{
List<SelectListItem> languages = _dbcontext.Languages.AsNoTracking()
.Where(n => n.IsActive == true)
.OrderBy(n => n.LanguageName)
.Select(n =>
new SelectListItem
{
Value = n.LanguageID.ToString(),
Text = n.LanguageName
}).ToList();
return new SelectList(languages, "Value", "Text");
}
}
*** js block***
$("#LanguageDropDown").chosen({
placeholder_text_multiple: "Select Language(s)",
});
Change your code like below:
<form asp-action="test">
#Html.ListBoxFor(model => model.Language, new MultiSelectList(Model.Languages, "Value", "Text"), htmlAttributes: new { id = "LanguageDropDown", multiple = "multiple", #class = "listbox-text" })
#Html.ValidationMessageFor(m => m.Language)
<div>
<input type="submit" value="submit" />
</div>
</form>
#section Scripts
{
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<link rel="stylesheet" href="~/lib/chosen_v1.8.7/docsupport/prism.css">
<link rel="stylesheet" href="~/lib/chosen_v1.8.7/docsupport/style.css">
<link rel="stylesheet" href="~/lib/chosen_v1.8.7/chosen.css">
<script src="~/lib/chosen_v1.8.7/chosen.jquery.js"></script>
<script src="~/lib/chosen_v1.8.7/docsupport/prism.js"></script>
<script src="~/lib/chosen_v1.8.7/docsupport/init.js"></script>
<script>
$("#LanguageDropDown").chosen({
placeholder_text_multiple: "Select Language(s)"
});
$.validator.setDefaults({
ignore: []
});
</script>
<style>
#LanguageDropDown-error {
color: red;
}
</style>
}
Result:

posting data from partial view on main view then submitting to controller

I have a MVC model as follows
public class ListSampleModel
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int SampleId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PointOfContact> lstPoc { get; set; }
}
public class PointOfContact
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int PocID { get; set; }
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
}
What I have done is, create "PointOfContact" as a partial view on a jquery dialog and on "save" button click it shows the data on the main view in labels (I will have multiple point of contacts), now on submit I want this data along with the property values of ListSampleData to be posted back to the controller.
The issue is, the data related to simple properties are returned back but the list is always null.
below is my View
#model MVCDataFlowSample.Models.ListSampleModel
#using (Html.BeginForm("Create", "ListSample", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ListSampleModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div id="dialog1" class="ui-dialog" style="background-color:gray;"></div>
<div id="data">
</div>
<p>
<input type="button" value="Add More..." id="btnAdd" />
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Javascript on Main View
<script type="text/javascript">
$(document).ready(function () {
$('#btnAdd').on('click', function () {
$('#dialog1').dialog({
autoOpen: true,
position: { my: "center", at: "center", of: window },
width: 1000,
resizable: false,
title: 'Add User Form',
modal: true,
open: function () {
$(this).load('#Url.Action("PocPartial", "ListSample")');
},
buttons: {
"Save User": function () {
addUserInfo();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
return false;
});
function addUserInfo(email, phone) {
var text = "<div id='EmailAddress'>Email Address:" + $("#EAddress").val() + "</div><div id='PhoneNumber'>Phone Number:" + $("#PhNo").val() + "</div>";
$("#data").append(text);
}
});
</script>
Partial View
#model MVCDataFlowSample.Models.PointOfContact
<div>
#Html.Label("EmailAddress:")
<div>
#Html.TextBoxFor(x => x.EmailAddress, new { id = "EAddress" })
</div>
#Html.Label("PhoneNumber:")
<div>
#Html.TextBoxFor(x => x.PhoneNumber, new { id = "PhNo" })
</div>
</div>
any help will be appreciated.
The contents of DIV elements are not submitted as form data. If you'd like that data to be submitted, add it to the DOM as hidden INPUT elements in addition to your DIVs. You'll also need to format their names correctly so that MVC knows how to bind them. See this article for how complex objects are bound in MVC.
I posted partial view data to the main page's post action You can modify the idea to any of your suits
Partial View
<select name="Country">
<option>Indian</option>
<option>Africa</option>
</select>
<select name="State">
<option>Kerala</option>
<option>TamilNadu</option>
</select>
<select name="City">
<option>Thrissur</option>
<option>Palakkad</option>
</select>
Index Page
#{
ViewBag.Title = "IndexTestPost";
}
<h2>IndexTestPost</h2>
#using(Html.BeginForm()){
#Html.Partial("~/Views/_PartialPagePostCountry.cshtml");
<input type="submit" />
}
Class To Catch Post Data
public class CountryCityState
{
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
}
Controller
public class TestPostPartialController : Controller
{
// GET: TestPostPartial
public ActionResult IndexTestPost()
{
return View();
}
[HttpPost]
public ActionResult IndexTestPost(CountryCityState CtnCtySta)
{
return View();
}
}

Disable day in date picker

I am trying to make an appointment page in MVC4. It is working well but I would like to disable the date which is chosen. Here is my controller to make an appointment:
public ActionResult Make()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Make(Models.AppModel User)
{
if (Session["UserEmail"] != null)
{
using (var db = new MaindbModelDataContext())
{
var patient = db.Patients.FirstOrDefault(u => u.Email == (String)Session["UserEmail"]);
var app = new Appointment();
app.Date = (DateTime)User.Date;
app.Description = User.Description;
app.Status = "isPending";
app.PatientNo = patient.PatientNo;
app.AppNo = Guid.NewGuid().GetHashCode();
db.Appointments.InsertOnSubmit(app);
db.SubmitChanges();
}
}
else
{
return RedirectToAction("Index", "User");
}
return RedirectToAction("Index", "Patient");
}
//
}
}
and here is my view with the datepicker
#model DentAppSys.Models.AppModel
#{
ViewBag.Title = "Appointment";
}
<link type="text/css" rel="stylesheet" href="//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken();
#Html.ValidationSummary(true, "");
<div>
<fieldset>
<legend>Get an Appointment</legend>
<div>#Html.LabelFor(u => u.Date)</div>
<div>
#Html.TextBoxFor(u => u.Date, htmlAttributes: new { id = "DatePicker" })
#Html.ValidationMessageFor(u => u.Date)
</div>
<div>#Html.LabelFor(u => u.Description)</div>
<div>
#Html.TextBoxFor(u => u.Description)
</div>
<input type="submit" value="Submit" class="footer_btn" />
</fieldset>
</div>
}
<script type="text/javascript">
$(function () {
$("#DatePicker").datepicker();
});
</script>
How about trying:
#Html.TextBoxFor(u => u.Date, htmlAttributes: new { id = "DatePicker", readonly = "readonly" })

One individual jQuery UI DatePicker not working

I have three text inputs on a view. All have the class datepicker.
#Html.TextBox("Dummy", DateTime.Now, new { #class = "datepicker" })
#Html.EditorFor(model => model.StartDate)
#Html.EditorFor(model => model.EndDate)
The bottom two are covered by my DateTime editor template:
#model DateTime?
#{
string editText = Model.HasValue ? Model.Value.ToShortDateString() : "";
}
#Html.TextBox("", editText, new { #class = "datepicker" })
These are set up for date pickers in my _Layout template in the following code:
$(function () {
$(".datepicker").datepicker({
dateFormat: "yy/mm/dd"
});
});
Now the date picker popup for StartDate, only, is totally unresponsive. It won't even change months, never mind pick a date. All three inputs are the same. Both StartDate and EndDate are non-nullable DateTime fields declared as:
[Display(Name = "Start Date")]
public DateTime StartDate { get; set; }
[Display(Name = "End Date")]
public DateTime EndDate { get; set; }
I am using jQuery 1.10.2 and jQuery UI 1.10.3, both installed via NuGet. I had to include the following script to get the DatePickers working:
<script src="http://code.jquery.com/jquery-migrate-1.1.1.js"></script>
I am totally stymied.
AMENDMENT:
Errors show in the Javascript console:
Clicking on a day produces the error "Cannot set property 'currentDay' of undefined".
Clicking on the previous or next month icon produces "Cannot read property 'settings' of undefined"
I guess you don't have an unique id for the textbox?
an unique id is required for the datepicker.
either add it in the javascript
$(function () {
$(".datepicker:not(.hasdatepicker)").uniqueId().datepicker({
dateFormat: "yy/mm/dd"
});
});
or add it in razor
#Html.TextBox("", editText, new { #class = "datepicker", id = string.Format("datepicker-{0:N}", Guid.NewGuid()) })
I've used exact version of each script file (jQuery,jQuery UI, jQuery migrate) and used your code and found no error. It works fine without any issue.
Modal:
public class Test
{
[Display(Name = "Start Date")]
public DateTime StartDate { get; set; }
[Display(Name = "End Date")]
public DateTime EndDate { get; set; }
}
Edit View:
#model MvcApplication2.Models.Test
#{
ViewBag.Title = "Test";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Test</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Test</legend>
<div class="editor-label">
#Html.LabelFor(model => model.StartDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.StartDate)
#Html.ValidationMessageFor(model => model.StartDate)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.EndDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.EndDate)
#Html.ValidationMessageFor(model => model.EndDate)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Shared/EditorTemplates/DateTime.Cshtml
#model DateTime?
#{
string editText = Model.HasValue ? Model.Value.ToShortDateString() : "";
}
#Html.TextBox("", editText, new { #class = "datepicker" })
<script type="text/javascript">
$(function () {
$(".datepicker").datepicker({
dateFormat: "yy/mm/dd"
});
});
</script>
Below is the order of CSS and JS files.
#Styles.Render("~/Content/css")
#Styles.Render("~/Content/themes/base/jquery-ui.css")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/Scripts/jquery-migrate-1.1.1.js")
#Scripts.Render("~/bundles/jqueryui")
#Scripts.Render("~/bundles/modernizr")
It seems something else is causing the issue and not any script file or anything else. You might want to try my code in new project.
Use this link for more info: http://jqueryui.com/datepicker/
And try to change mm to MM
$(function () {
$(".datepicker").datepicker({
dateFormat: "yy/MM/dd"
});
});
Second answer:
Try using this date/time picker:
http://tarruda.github.io/bootstrap-datetimepicker/
or
http://www.eyecon.ro/bootstrap-datepicker/
I used them both, and worked for me.
Hope this helpes.

How to validate Date in ClientSide using FluentValidation?

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>
There are things I don't understand about your settings and about what is not working. Do you mean the verification that the date must be valid is not working, or that the fact the date is required is not working?
Fluent validation is able to emit code for unobtrusive validation too, so the required constraint should work properly.
The fact that the date is valid is completely another story. If you specify your FromDate as a DateTime (have you declared it as a DateTime or as a string?) the verification of correctness of date is AUTOMATICALLY performed by other validators included in the Mvc framework, so you dont need to repeat it in the fluent validation rules. However, before Mvc4 this validation check were performed ONLY on the server side. With Mvc 4 the Asp.net Mvc Team fixed this problem and extended the check also on the client side.
However, on the client side, everything work propery only for the en-US date format, , since unobtrusive validation doesn't handle globalization. If you need date in other cultures you need to use the Globalize library, and you need to set up globalization on the client side. If you are interested to globalization you may see this post of my blog.
To add automatic Date correction also to Mvc 3. You must define an extended ClientDataTypeModelValidatorProvider like the one of Mvc4. Below the code:
public class ClientDataTypeModelValidatorProviderExt : ClientDataTypeModelValidatorProvider
{
public static Type ErrorMessageResources { get; set; }
public static string NumericErrorKey { get; set; }
public static string DateTimeErrorKey { get; set; }
private static readonly HashSet<Type> _numericTypes = new HashSet<Type>(new Type[] {
typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort),
typeof(int), typeof(uint),
typeof(long), typeof(ulong),
typeof(float), typeof(double), typeof(decimal)
});
private static bool IsNumericType(Type type)
{
Type underlyingType = Nullable.GetUnderlyingType(type); // strip off the Nullable<>
return _numericTypes.Contains(underlyingType ?? type);
}
internal sealed class NumericModelValidator : ModelValidator
{
public NumericModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
: base(metadata, controllerContext)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
ModelClientValidationRule rule = new ModelClientValidationRule()
{
ValidationType = "number",
ErrorMessage = MakeErrorString(Metadata.GetDisplayName())
};
return new ModelClientValidationRule[] { rule };
}
private static string MakeErrorString(string displayName)
{
// use CurrentCulture since this message is intended for the site visitor
return String.Format(CultureInfo.CurrentCulture, ErrorMessageResources.GetProperty(NumericErrorKey, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).GetValue(null, null) as string, displayName);
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
// this is not a server-side validator
return Enumerable.Empty<ModelValidationResult>();
}
}
internal sealed class DateTimeModelValidator : ModelValidator
{
public DateTimeModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
: base(metadata, controllerContext)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
ModelClientValidationRule rule = new ModelClientValidationRule()
{
ValidationType = "globalizeddate",
ErrorMessage = MakeErrorString(Metadata.GetDisplayName())
};
return new ModelClientValidationRule[] { rule };
}
private static string MakeErrorString(string displayName)
{
// use CurrentCulture since this message is intended for the site visitor
return String.Format(CultureInfo.CurrentCulture, ErrorMessageResources.GetProperty(DateTimeErrorKey, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).GetValue(null, null) as string, displayName);
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
// this is not a server-side validator
return Enumerable.Empty<ModelValidationResult>();
}
}
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata == null)
{
throw new ArgumentNullException("metadata");
}
if (context == null)
{
throw new ArgumentNullException("context");
}
List<ModelValidator> res = null;
if (NumericErrorKey == null || ErrorMessageResources == null)
res = base.GetValidators(metadata, context).ToList();
else
{
res = new List<ModelValidator>();
if (IsNumericType(metadata.ModelType))
{
res.Add(new NumericModelValidator(metadata, context));
}
}
if ( (metadata.ModelType == typeof(DateTime) || metadata.ModelType == typeof(DateTime?)))
{
if(ErrorMessageResources != null && DateTimeErrorKey != null)
res.Add(new DateTimeModelValidator(metadata, context));
}
return res;
}
}
Then in the global.asax you must substititute the standard one with this:
var old = ModelValidatorProviders.Providers.Where(x => x is ClientDataTypeModelValidatorProvider).FirstOrDefault();
if (old != null) ModelValidatorProviders.Providers.Remove(old);
ModelValidatorProviders.Providers.Add(new ClientDataTypeModelValidatorProviderExt());
Now you have to add the javascript snipped that do the control on the client side:
$.validator.addMethod(
"globalizeddate",
function (value, element, param) {
if ((!value || !value.length) && this.optional(element)) return true; /*success*/
var convertedValue = Globalize.parseDate(value);
return !isNaN(convertedValue) && convertedValue;
},
"field must be a date/time"
);
There I used the Globalize function to verify correct date. Install it. It is the only way to have a date frormat compatible with the .net format. Moreover it works in all .net cultures. Using a standard javascript date parsing, is not compatible with the formats accepted by .Net in some browsers.
In MVC 3 below code should work fine.
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#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" />
}
Simple working Example in MVC 4
_Layout.cshtml:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title - My ASP.NET MVC Application</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div id="body">
#RenderSection("featured", required: false)
<section class="content-wrapper main-content clear-fix">
#RenderBody()
</section>
</div>
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts", required: false)
</body>
</html>
View:
#model Mvc4Test.Models.Person
#{
ViewBag.Title = "test";
}
<h2>test</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Part</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
For more details.

Resources