views:

2077

answers:

5

I am using ASP.NET MVC2 with MvcContrib.FluentHtml to do form binding.

I want to bind a DateTime format to a textbox with specific datetime format.

<%=this.TextBox(c => c.date_a).Class("readonly text-box") %>
// PS. c.date_a is a DateTime

gives me

<input type="text" value="5/9/2009 12:00:00 AM" name="date_a" id="datea" class="readonly text-box">

However, I'd like to override the default datetime format. e.g.

value="2009-5-9" 
value="9-5-09" 
value="09May9" 

I know I can override the value by specific a value, however, the date should also bind to the object class on POST the form.

How to do "minimum" code to override the default datetime format of a specific field on UI?

A: 

I am not sure whether this would cause you problems when the value is posted back but the following syntax should allow you to change the format with which the date value is displayed.

<%=this.TextBox(c => c.date_a.ToString('yyyy-M-d')).Class("readonly text-box") %>

You will find further information on how to construct the format strings here.

Scott Munro
How can I capture the date value in another format with TryUpdateModel?
Dennis Cheung
This won't work. The lambda name in extension method tells FluentHtml how to bind the element.
Tim Scott
A: 

First, add this extension for getting property path:

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 extensions for HtmlHalper:

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" }) %>
Сергій
Interesting use of regex. But kind a messy approach.
Arnis L.
I cannot see how it works with binding. Anyone can explain?
Dennis Cheung
It just creates a correct name. This all that you need to bind input to the model's field.
Сергій
+5  A: 

I don't know if this work with MvcContrib MvcContrib.FluentHtml but without it, it is very simple, add to your model property

[DisplayFormat(DataFormatString="{0:MM/dd/yyyy}", ApplyFormatInEditMode=true)]

and in your view

<%= Html.EditorFor(m => m.DateProperty) %>

I Don't know if MvcContrib uses Attributes but if it doesn't, it should, that way, you'll always have your date the same format, specifying the format only once...

hope this help

moi_meme
As far as i know - it does not.
Arnis L.
I would go with this approach unless you mean domain model (instead of view model).
Arnis L.
It looks clean and good, however, I am using LINQ2SQL that is difficult to add DisplayFormatAttribute to property in generated code.
Dennis Cheung
You can simply define a validator class check http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx for an example
moi_meme
Thanks, I had this same problem. Any reason why [DisplayFormat] doesn't work with TextBoxFor()?
Lucas
I'm not sure but the EditorHelper calls the TextBoxHelper sending it the formated value... and the textBoxHelper doesn't even check for that.
moi_meme
The problem with using an attribute in this way is that you're bolting a view concern onto the data object. What if I want "3/8/10" when showing in a grid, but "March 8, 2010" in the detail? A common scenario. Do the formatting in the view, where that concern belongs.
Tim Scott
A: 

I often run into situations where it's impractical to modify the model (with attributes etc) so being able to implement a solution like Сергій's is important. To Dennis Cheung point though, you can more tightly bind this solution as follows:

public static MvcHtmlString DateBoxFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, DateTime?>> property)
{
    return helper.DateBoxFor(property, "d", null);
}

public static MvcHtmlString DateBoxFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, DateTime?>> property, string format, object htmlAttributes)
{
    var viewData = helper.ViewContext.ViewData;
    var date = property.Compile().Invoke(viewData.Model);
    var value = date.HasValue ? date.Value.ToString(format) : string.Empty;
    var name = viewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(property));

    return helper.TextBox(name, value, htmlAttributes);
}

Then you call it like this:

<%:Html.DateBoxFor(m => m.SomeDate)%>

Or like this:

<%:Html.DateBoxFor(m => m.SomeDate, "d", null)%>
CodeSponge
A: 

With FluentHtml you can do like this:

<%=this.TextBox(c => c.date_a).Class("readonly text-box").Format("yyyy-M-d") %>
Tim Scott