Reputation: 1339
I couldn't find a complete solution for using JQuery date picker in MVC3 and from what I found on different pages I came up with my solution which still does not work as I want it to. I have the following:
The model:
public class Some
{
[Display(Name = "DateCreated", ResourceType = typeof(Resources))]
[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "RequiredField")]
[DataType(DataType.Date, ErrorMessage = "Date non valid.")]
[DisplayFormat(NullDisplayText = "NotSpecified", DataFormatString = "{0:dd.MM.yyyy.}")]
public DateTime DateCreated { get; set; }
}
I am decorating the property cause I want the client and the server side validation and text.
I am using the Home controller for this example and I have:
public ActionResult Index()
{
Some model = new Some { DateCreated = DateTime.Now };
return View(model);
}
[HttpPost]
public ActionResult Index(Some model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(model);
}
The view:
@model TestDatePicker.Models.Some
@using (Html.BeginForm())
{
<div class="editor-label">
@Html.LabelFor(model => model.DateCreated)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.DateCreated)
@Html.ValidationMessageFor(model => model.DateCreated)
</div>
<p>
<input type="submit" value="Save" />
</p>
}
And a custom template for rendering the field with DateTime type:
@model Nullable<System.DateTime>
@{
string controlName = ViewData.TemplateInfo.HtmlFieldPrefix;
string controlId = controlName.Replace(".", "_");
if ( Model.HasValue ) {
@Html.TextBox("", String.Format("{0:dd.MM.yyyy.}", Model.Value), new { @class = "textbox", name = controlName })
}
else {
@Html.TextBox("", String.Format("{0:dd.MM.yyyy.}", DateTime.Now), new { @class = "textbox", name = controlName })
}
}
}
<script type="text/javascript">
$(document).ready(function () {
$(".textbox").datepicker
({
dateFormat: 'dd.mm.yy.',
showStatus: true,
showWeeks: true,
highlightWeek: true,
numberOfMonths: 1,
showAnim: "scale",
showOptions: {
origin: ["top", "left"]
},
onClose: function () {
$(this).valid();
}
});
});
</script>
What is happening with this code? The value for the DateTime filed is assigned in the custom template and it is shown as today's date.
Interesting this is that if you use the datepicker and select a data from it, you get the property in the model populated. And Model.IsValid is TRUE.
This is how the html for the input control looks like:
<input class="textbox" data-val="true" data-val-required="Requred field" id="DateCreated" name="DateCreated" type="text" value="26.05.2012." />
Is the JQueryUI date picker not the best choice for ASP.NET MVC? It seems that, whit this solution of the custom template that I see all over the net, the basic MVC stuff is not even working? Does anyone know of any complete tutorial on doing this? I can't be the first person facing these problems.
Thank you.
I have downloaded the code that is created in the blog post everyone refers to when talking about MVC3 and datepicker and the SAME thing is happening there!
Upvotes: 1
Views: 3860
Reputation: 2123
Theres nothing in your template that binds between your model and the datetime value you are providing.
When a form is submited, mvc needs to know how to fill the Some object with the values from the form. This works with standart editors, because they use the binded propety name as the id/name for the client side inputs. You didnt do this with your custom editor, and therefor when the form is submited, theres no way for mvc to tell your custom editor actually supplies the DateCreated property.
Add the name / id attributes to the underlying input in your editor to make this work (or use the standart provided editor, and the look at the html source of ur page in the browser / any kind of a networking sniffer to see exactly how it works)
EDIT: my complete version of the code, that works
model:
public class Some
{
[Display(Name = "DateCreated")]
[Required(ErrorMessage="failed")]
[DataType(DataType.Date, ErrorMessage = "Date non valid.")]
[DisplayFormat(NullDisplayText = "NotSpecified", DataFormatString = "{0:dd.MM.yyyy.}")]
public DateTime DateCreated { get; set; } }
controller:
public class DefaultController : Controller
{
public ActionResult Index()
{
Some model = new Some { DateCreated = DateTime.Now };
return View(model);
}
[HttpPost]
public ActionResult Index(Some model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(model);
}
}
index view:
@model Some
@using (Html.BeginForm())
{
<div class="editor-label">
@Html.LabelFor(model => model.DateCreated)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.DateCreated)
@Html.ValidationMessageFor(model => model.DateCreated)
</div>
<p>
<input type="submit" value="Save" />
</p>
}
date editor:
@model Nullable<DateTime>
@{
string controlName = ViewData.TemplateInfo.HtmlFieldPrefix;
string controlId = controlName.Replace(".", "_");
if ( Model.HasValue )
{
@Html.TextBox("", String.Format("{0:dd.MM.yyyy.}", Model.Value),
new {@class "textbox", name = controlName })
}
else
{
@Html.TextBox("", String.Format("{0:dd.MM.yyyy.}", DateTime.Now),
new { @class = "textbox", name = controlName })
}
}
<script type="text/javascript">
$(document).ready(function () {
$(".textbox").datepicker({
dateFormat: 'dd.mm.yy.',
showStatus: true,
showWeeks: true,
highlightWeek: true,
numberOfMonths: 1,
showAnim: "scale",
showOptions: { origin: ["top", "left"] },
onClose: function () { $(this).valid(); }
});
});
</script>
included scripts:
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")"
type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.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>
it works 100% on my side, with our without the jquery datepicker. I change the usage of the attributes a tiny bit, and didnt provide resources for them. as far as i understand, btw, the DataType attribute is useless in this scenario.
Upvotes: 2