I want to create an editor template for DateTime
, I need 3 separated fields:
(DropDown) Day | (DropDown) Month | (DropDown) Year
How and where do I create this file? And what do I need to do to turn these 3 fields into a single DateTime
when I post to a controller?
In your Views/Shared/EditorTemplates
folder create a partial view called DateTime.ascx
.
The code for this EditorTemplate should be something like
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %>
<%
string controlId = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('.', '_');
%>
<script type="text/javascript">
$(function () {
$('#<%: controlId %>_Day, #<%: controlId %>_Month, #<%: controlId %>_Year').live('change', function () { updateHiddenDate('<%: controlId %>'); });
$('#<%: controlId %>_Day').val('<%: Model.HasValue ? Model.Value.Day.ToString() : "" %>');
$('#<%: controlId %>_Month').val('<%: Model.HasValue ? Model.Value.Month.ToString() : "" %>');
$('#<%: controlId %>_Year').val('<%: Model.HasValue ? Model.Value.Year.ToString() : "" %>');
updateHiddenDate('<%: controlId %>');
});
function updateHiddenDate(hiddenDateId) {
$('#' + hiddenDateId).val($('#' + hiddenDateId + '_Year').val() + "-" + $('#' + hiddenDateId + '_Month').val() + "-" + $('#' + hiddenDateId + '_Day').val());
}
</script>
<select id="<%: controlId %>_Day">
<% for (int dayOrdinal = 1; dayOrdinal <= 31; dayOrdinal++)
{
Response.Write(string.Format("<option value=\"{0}\">{0}</option>", dayOrdinal));
}
%>
</select>
<select id="<%: controlId %>_Month">
<% for (int monthOrdinal = 1; monthOrdinal <= 12; monthOrdinal++)
{
Response.Write(string.Format("<option value=\"{0}\">{1}</option>", monthOrdinal, System.Globalization.DateTimeFormatInfo.CurrentInfo.MonthNames[monthOrdinal - 1]));
}
%>
</select>
<select id="<%: controlId %>_Year">
<% for (int yearOrdinal = DateTime.Now.Year - 5; yearOrdinal <= DateTime.Now.Year + 5; yearOrdinal++)
{
Response.Write(string.Format("<option value=\"{0}\">{0}</option>", yearOrdinal));
}
%>
</select>
<%: Html.Hidden("", Model.HasValue ? String.Format("{0:yyyy-MM-dd}", Model) : "") %>
That creates an editor template with a hidden field containing an ISO 8601 representation of the date which the MVC ModelBinder can parse.
The jQuery updates the hidden field whenever the dropdowns change. Note the use of the ViewData.TemplateInfo.HtmlFieldPrefix
that I use to get the generated id
of the hidden field.
Note that this solution drops in easily without faffing about with Custom ModelBinders because we construct a single form value containing the full datetime. However, this does mean that
<script type="text/javascript" src="../../Scripts/jquery-1.4.1.min.js"></script>
)If that's not acceptable, you will have to look at Custom ModelBinders as @Jon has pointed to.
Scott Hanselman has a blog post on creating a custom model binder to handle DateTime
s. It doesn't exactly fit your scenario, but it should give you some ideas, and once that's in place the editor template should be much easier...
In terms of where to place the file once it's created - that's the easy bit:
~/Views/Shared/EditorTemplates/DateTime.[ascx|cshtml|vbhtml]
Editor Templates are your best bet. If you want the editor template available from anywhere, put it in the Views/Shared/EditorTemplates folder. If you want all DateTime
types to use this template, then create a partial called DateTime
. If you only want some of them to use this template, then call it something else, and use the UIHintAttribute
attribute and create an editor template with the same name as the value you use for that attribute.
To have the model binder continue working, you may need to add some javascript to your editor, and onchange for any of the drop dropdowns should update a hidden field (with the correct name so the model binder will work) with the selected month/day/year values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With