MVC4 DataType.Date EditorFor won't display date value in Chrome, fine in Internet Explorer
Asked Answered
S

8

205

I'm using the DataType.Date attribute on my model and an EditorFor in my view. This is working fine in Internet Explorer 8 and Internet Explorer 9, but in Google Chrome it is showing a date picker and instead of displaying the value it just displays "Month/Day/Year" in faded gray text.

Why won't Google Chrome display the value?

Model:

[DataType(DataType.Date)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }

View:

<td class="fieldLabel">Est. Pur. Date</td>
<td class="field">@Html.EditorFor(m=>m.EstPurchaseDate)</td>

Chrome

Internet Explorer

Scholasticism answered 28/9, 2012 at 4:12 Comment(0)
F
393

When you decorate a model property with [DataType(DataType.Date)] the default template in ASP.NET MVC 4 generates an input field of type="date":

<input class="text-box single-line" 
       data-val="true" 
       data-val-date="The field EstPurchaseDate must be a date."
       id="EstPurchaseDate" 
       name="EstPurchaseDate" 
       type="date" value="9/28/2012" />

Browsers that support HTML5 such Google Chrome render this input field with a date picker.

In order to correctly display the date, the value must be formatted as 2012-09-28. Quote from the specification:

value: A valid full-date as defined in [RFC 3339], with the additional qualification that the year component is four or more digits representing a number greater than 0.

You could enforce this format using the DisplayFormat attribute:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }
Fortissimo answered 28/9, 2012 at 6:6 Comment(12)
Darin thank you, that was perfect! You've answered so many of my MVC questions over the past two years, you rock!Scholasticism
Great answer but I feel this is appealing you have to force it just to get the control to work properly!Ventose
What would be the way of doing this "globally" for all properties marked [DataType(DataType.Date)] so I wouldn't have to mark all these properties separately with the risk of missing some?Pennoncel
Darin, What can us people outside USA do? How can I set the specification value but display a custom date format? ie, UK?Indictment
@ppumkin: This is not US specific. In fact, the reason the HTML5 specification uses YYYY-MM-DD is because it's an international standard (ISO 8601). If you need to display the date in a different format, you'll need to utilize view models in your views so that you can set the date format for your form to ISO 8601, but set the date format for something like a detail view to whatever the localized version you desire is.Shear
The format displayed in Chrome is whatever is set in your systems globalization settings. So, yes, set everything as per example in ISO 8601 but make sure the system is set to the correct Globale. After chaining it make sure to restart Chrome, Firefox.. not sure about IE or other browsers.Indictment
@MarjanVenema - I've hooked into the Model Metadata and I add this to the DisplayFormatString and to the EditFormatString.Cartload
@SwampyFox: Thanks! (Any references on how to do this?)Pennoncel
@MarjanVenema- I've used the "ExtensibleModelMetadataProvider" from Matt Honeycutt's FailTracker (github.com/MattHoneycutt/Fail-Tracker). Look under the Infrastructure Folder to the ModelMetadata. I've used those classes and then created an filter implementation of IModelMetadataFilter. When the TransformMetadata method is called, you can then edit the "DisplayFormatString" and "EditFormatString" properties of the metadata. Hope this gets you in the right direction (btw, there is a great pluralsight video that uses Fail-Tracker)Cartload
Its not working for me. Year part in date picker accepting upto 6 digits. How can i restrict to 4 digits. Heres my code : [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] [DataType(DataType.Date, ErrorMessage = "Please enter a valid date in the format MM/DD/YYYY")] [Display(Name = "Date of Birth:")] [Required] public string DOB { get; set; }Sideband
Maaann, i was searching for this and I finally got it! thank you!!Sarcous
Great answer! I had the same problem with 0:MM/dd/yyyy instead of the other way around - 0:yyyy-MM-dd. This worked (the commented-out annotations is what I originally had in my model:[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] //[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] [DataType(DataType.Date)]Ambulant
N
45

In MVC5.2, add Date.cshtml to folder ~/Views/Shared/EditorTemplates:

@model DateTime?
@{
    IDictionary<string, object> htmlAttributes;
    object objAttributes;
    if (ViewData.TryGetValue("htmlAttributes", out objAttributes))
    {
        htmlAttributes = objAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(objAttributes);
    }
    else
    {
        htmlAttributes = new RouteValueDictionary();
    }
    htmlAttributes.Add("type", "date");
    String format = (Request.UserAgent != null && Request.UserAgent.Contains("Chrome")) ? "{0:yyyy-MM-dd}" : "{0:d}";
    @Html.TextBox("", Model, format, htmlAttributes)
}
Nephridium answered 13/11, 2014 at 22:0 Comment(6)
thanks! fixes the mentioned chrome "issue" and of course you can have another displayformat on your datetime property!Stodgy
Yes great solution. This provides an excellent work around for those of us not in the US.Alchemize
I think this is the best solution to the problem, it fixes just the editor issue and doesn't affect existing display formatting.Brittani
Using "Date.cshtml" instead of "DateTime.cshtml" was the magic answer! It works in MVC 4 as well.Humfrid
Great! Obrigado.Horsetail
Had to stick with DateTime.cshtml instead of the recommended Date, but after a couple tweaks it worked great! One of my key changes was using the pre-formatted value (generated using the model property's specified DisplayFormat), which made the last line: @Html.TextBox(ViewData.TemplateInfo.HtmlFieldPrefix, ViewData.TemplateInfo.FormattedModelValue, htmlAttributes)Hyman
P
19

As an addition to Darin Dimitrov's answer:

If you only want this particular line to use a certain (different from standard) format, you can use in MVC5:

@Html.EditorFor(model => model.Property, new {htmlAttributes = new {@Value = @Model.Property.ToString("yyyy-MM-dd"), @class = "customclass" } })
Phan answered 19/12, 2014 at 12:47 Comment(2)
As there is @ at the beginning, that @Value = @Model.Property... still need that @? Do you mean just new { Value = Model.Property...?Countervail
Can confirm, @user3454439Fanya
C
11

In MVC 3 I had to add:

using System.ComponentModel.DataAnnotations;

among usings when adding properties:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

Especially if you are adding these properties in .edmx file like me. I found that by default .edmx files don't have this using so adding only propeties is not enough.

Carabin answered 3/1, 2013 at 11:46 Comment(0)
M
10

If you remove [DataType(DataType.Date)] from your model, the input field in Chrome is rendered as type="datetime" and won't show the datepicker either.

Mcquade answered 4/10, 2012 at 10:55 Comment(3)
Thanks Bernie. I wasn't so trouble with the picker showing up as I was with the data not being put into the input box. This is good to know though.Scholasticism
Opera renders a datepicker though. Use modernizr to do some polyfillBiocatalyst
If it's supposed to be a date, it should be rendered as an input of type date. Using datetime as a work-around is inappropriate, since it doesn't semantically represent the data.Shear
A
4

I still had an issue with it passing the format yyyy-MM-dd, but I got around it by changing the Date.cshtml:

@model DateTime?

@{
    string date = string.Empty;
    if (Model != null)
    {
        date = string.Format("{0}-{1}-{2}", Model.Value.Year, Model.Value.Month, Model.Value.Day);
    }

    @Html.TextBox(string.Empty, date, new { @class = "datefield", type = "date"  })
}
Adda answered 29/11, 2012 at 13:9 Comment(1)
thank you finally this worked, i tried string.Format("{0}/{1}/{2}") to get dd/mm/yyyy format, and it works fine, i used database first method but DisplayFormat didn't worked with partial class, don't know why?, anyway anyone if needed try this method , i didn't try but if anyone needed , hope it helpsBackbone
M
3

Reply to MVC4 DataType.Date EditorFor won't display date value in Chrome, fine in IE

In the Model you need to have following type of declaration:

[DataType(DataType.Date)]
public DateTime? DateXYZ { get; set; }

OR

[DataType(DataType.Date)]
public Nullable<System.DateTime> DateXYZ { get; set; }

You don't need to use following attribute:

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

At the Date.cshtml use this template:

@model Nullable<DateTime>
@using System.Globalization;

@{
    DateTime dt = DateTime.Now;
    if (Model != null)
    {
        dt = (System.DateTime)Model;

    }

    if (Request.Browser.Type.ToUpper().Contains("IE") || Request.Browser.Type.Contains("InternetExplorer"))
    {
        @Html.TextBox("", String.Format("{0:d}", dt.ToShortDateString()), new { @class = "datefield", type = "date" })
    }
    else
    {
        //Tested in chrome
        DateTimeFormatInfo dtfi = CultureInfo.CreateSpecificCulture("en-US").DateTimeFormat;
        dtfi.DateSeparator = "-";
        dtfi.ShortDatePattern = @"yyyy/MM/dd"; 
        @Html.TextBox("", String.Format("{0:d}", dt.ToString("d", dtfi)), new { @class = "datefield", type = "date" })
    } 
}

Have fun! Regards, Blerton

Mauri answered 31/12, 2013 at 13:32 Comment(2)
If you do it this way, Chrome won't give you a date picker. I'm using your solution, but modifying so that 1) I DO use the DisplayFormat attribute 2) Change the test to check if the browser type is chrome, then do @Html.EditorFor(m=>m.EstPurchaseDate) 3) Else do @Html.TextBox("EstPurchaseDate", dt.ToString("MM/dd/yyyy")) Note: on #2, a better check would be if the browser understands HTML5, but I don't know how to do that.Feminine
Downvoting for browser detection in server side code.Elmer
R
2

If you need to have control over the format of the date (in other words not just the yyyy-mm-dd format is acceptable), another solution could be adding a helper property that is of type string and add a date validator to that property, and bind to this property on UI.

    [Display(Name = "Due date")]
    [Required]
    [AllowHtml]
    [DateValidation]
    public string DueDateString { get; set; }

    public DateTime? DueDate 
    {
        get
        {
            return string.IsNullOrEmpty(DueDateString) ? (DateTime?)null : DateTime.Parse(DueDateString);
        }
        set
        {
            DueDateString = value == null ? null : value.Value.ToString("d");
        }
    }

And here is a date validator:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class DateValidationAttribute : ValidationAttribute
{
    public DateValidationAttribute()
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            DateTime date;

            if (value is string)
            {
                if (!DateTime.TryParse((string)value, out date))
                {
                    return new ValidationResult(validationContext.DisplayName + " must be a valid date.");
                }
            }
            else
                date = (DateTime)value;

            if (date < new DateTime(1900, 1, 1) || date > new DateTime(3000, 12, 31))
            {
                return new ValidationResult(validationContext.DisplayName + " must be a valid date.");
            }
        }
        return null;
    }
}
Rolan answered 12/1, 2015 at 13:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.