Reputation: 18138
In my ASP.net MVC app I have a view that looks like this:
...
<label>Due Date</label>
<%=Html.TextBox("due")%>
...
I am using a ModelBinder
to bind the post to my model (the due property is of DateTime
type). The problem is when I put "01/01/2009" into the textbox, and the post does not validate (due to other data being input incorrectly). The binder repopulates it with the date and time "01/01/2009 00:00:00".
Is there any way to tell the binder to format the date correctly (i.e. ToShortDateString()
)?
Upvotes: 35
Views: 46584
Reputation: 551
I just came across this very simple and elegant solution, available in MVC 2:
Basically if you are using MVC 2.0, use the following in your view.
<%=Html.LabelFor(m => m.due) %>
<%=Html.EditorFor(m => m.due)%>
then create a partial view in /Views/Shared/EditorTemplates, called DateTime.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%=Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty), new { @class = "datePicker" }) %>
When the EditorFor<> is called it will find a matching Editor Template.
Upvotes: 55
Reputation: 51
MVC4 EF5 View I was trying to preload a field with today's date then pass it to the view for approval.
ViewModel.SEnd = DateTime.Now //preload todays date
return View(ViewModel) //pass to view
In the view, my first code allowed an edit:
@Html.EditedFor(item.SEnd) //allow edit
Later I changed it to just display the date, the user cannot change it but the submit triggers the controller savechanges
<td>
@Html.DisplyFor(item.SEnd) //show no edit
</td>
When I changed to DisplayFor I needed to add this to ensure the preloaded value was passed back to the controller. I also need to add HiddenFor's for every field in the viewmodel.
@Html.HiddenFor(model => model.SEnd) //preserve value for passback.
Beginners stuff but it took a while to work this out.
Upvotes: 0
Reputation: 26
Try this
<%:Html.TextBoxFor(m => m.FromDate, new { @Value = (String.Format("{0:dd/MM/yyyy}", Model.FromDate)) }) %>
Upvotes: 0
Reputation: 21108
This worked for me: mvc 2
<%: Html.TextBoxFor(m => m.myDate, new { @value = Model.myDate.ToShortDateString()}) %>
Simple and sweet!
A comment of user82646, thought I'd make it more visible.
Upvotes: 0
Reputation: 1563
I guess personally I'd say its best or easiest to do it via a strongly typed page and some defined model class but if you want it to be something that lives in the binder I would do it this way:
public class SomeTypeBinder : IModelBinder
{
public object GetValue(ControllerContext controllerContext, string modelName,
Type modelType, ModelStateDictionary modelState)
{
SomeType temp = new SomeType();
//assign values normally
//If an error then add formatted date to ViewState
controllerContext.Controller.ViewData.Add("FormattedDate",
temp.Date.ToShortDateString());
}
}
And then use that in the view when creating the textbox i.e. :
<%= Html.TextBox("FormattedDate") %>
Hope that helps.
Upvotes: 0
Reputation: 731
Decorate the property in your model with the DataType
attribute, and specify that its a Date
, and not a DateTime
:
public class Model {
[DataType(DataType.Date)]
public DateTime? Due { get; set; }
}
You do have to use EditorFor
instead of TextBoxFor
in the view as well:
@Html.EditorFor(m => m.Due)
Upvotes: 24
Reputation: 4517
First, add this extension for getting property path:
public static class ExpressionParseHelper
{
public static string GetPropertyPath<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
{
Match match = Regex.Match(property.ToString(), @"^[^\.]+\.([^\(\)]+)$");
return match.Groups[1].Value;
}
}
Than add this extension for HtmlHelper:
public static MvcHtmlString DateBoxFor<TEntity>(
this HtmlHelper helper,
TEntity model,
Expression<Func<TEntity, DateTime?>> property,
object htmlAttributes)
{
DateTime? date = property.Compile().Invoke(model);
var value = date.HasValue ? date.Value.ToShortDateString() : string.Empty;
var name = ExpressionParseHelper.GetPropertyPath(property);
return helper.TextBox(name, value, htmlAttributes);
}
Also you should add this jQuery code:
$(function() {
$("input.datebox").datepicker();
});
datepicker is a jQuery plugin.
And now you can use it:
<%= Html.DateBoxFor(Model, (x => x.Entity.SomeDate), new { @class = "datebox" }) %>
ASP.NET MVC2 and DateTime Format
Upvotes: 3
Reputation: 794
It's a dirty hack, but it seems to work.
<%= Html.TextBoxFor(model => model.SomeDate,
new Dictionary<string, object> { { "Value", Model.SomeDate.ToShortDateString() } })%>
You get the model binding, and are able to override the HTML "value" property of the text field with a formatted string.
Upvotes: 9
Reputation: 885
I find the best way to do this is to reset the ModelValue
ModelState.SetModelValue("due", new ValueProviderResult(
due.ToShortDateString(),
due.ToShortDateString(),
null));
Upvotes: 1
Reputation: 1252
Why don't you use
<% =Html.TextBox("due", Model.due.ToShortDateString()) %>
Upvotes: 4
Reputation: 5628
I found this question while searching for the answer myself. The solutions above did not work for me because my DateTime is nullable. Here's how I solved it with support for nullable DateTime objects.
<%= Html.TextBox(String.Format("{0:d}", Model.Property)) %>
Upvotes: 4
Reputation: 1563
In order to get strongly typed access to your model in the code behind of your view you can do this:
public partial class SomethingView : ViewPage<T>
{
}
Where T is the ViewData type that you want to pass in from your Action.
Then in your controller you would have an action :
public ActionResult Something(){
T myObject = new T();
T.Property = DateTime.Today();
Return View("Something", myObject);
}
After that you have nice strongly typed model data in your view so you can do :
<label>My Property</label>
<%=Html.TextBox(ViewData.Model.Property.ToShortDateString())%>
Upvotes: 1