MVC4 DataType.Date EditorFor nie wyświetla wartości daty w Chrome, dobrze w Internet Explorerze

198

Używam atrybutu DataType.Date w moim modelu i edytora ForFor w moim widoku. Działa to dobrze w Internet Explorerze 8 i Internet Explorerze 9 , ale w Google Chrome pokazuje selektor dat i zamiast wartości wyświetla tylko „Miesiąc / Dzień / Rok” wytartym szarym tekstem.

Dlaczego Google Chrome nie wyświetla wartości?

Model:

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

Widok:

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

Chrom

Internet Explorer

Ben Finkel
źródło

Odpowiedzi:

377

Podczas dekorowania właściwości modelu [DataType(DataType.Date)]domyślnym szablonem w ASP.NET MVC 4 generuje pole wejściowe 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" />

Przeglądarki obsługujące HTML5, takie jak Google Chrome, wyświetlają to pole wprowadzania za pomocą selektora daty.

Aby poprawnie wyświetlić datę, wartość należy sformatować jako 2012-09-28. Cytat ze specyfikacji :

wartość: ważna pełna data zdefiniowana w [RFC 3339], z dodatkową kwalifikacją, że składnikiem roku są cztery lub więcej cyfr reprezentujących liczbę większą niż 0.

Możesz wymusić ten format, używając DisplayFormatatrybutu:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }
Darin Dimitrov
źródło
44
Darin, dziękuję, to było idealne! Odpowiedziałeś na tak wiele moich pytań MVC w ciągu ostatnich dwóch lat, jesteś szalony!
Ben Finkel,
3
Świetna odpowiedź, ale uważam, że to pociągające, musisz ją zmusić, aby kontrola działała poprawnie!
Coops
7
Jaki byłby sposób robienia tego „globalnie” dla wszystkich oznaczonych właściwości, [DataType(DataType.Date)]więc nie musiałbym oznaczać wszystkich tych właściwości osobno, z ryzykiem ich utraty?
Marjan Venema
7
Darin, co my, ludzie poza USA, możemy zrobić? Jak ustawić wartość specyfikacji, ale wyświetlać niestandardowy format daty? tj. Wielka Brytania?
Piotr Kula,
3
@ MarjanVenema- Użyłem „ExtensibleModelMetadataProvider” z Matta Honeycutta FailTracker ( github.com/MattHoneycutt/Fail-Tracker ). Zajrzyj pod folder infrastruktury do ModelMetadata. Użyłem tych klas, a następnie utworzyłem implementację filtru IModelMetadataFilter. Po wywołaniu metody TransformMetadata można edytować właściwości metadanych „DisplayFormatString” i „EditFormatString”. Mam nadzieję, że to poprowadzi cię we właściwym kierunku (przy okazji, jest świetny pluralsight wideo, który wykorzystuje Fail-Tracker)
SwampyFox
44

W MVC5.2 dodaj Date.cshtml do folderu ~ / 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)
}
Charlie
źródło
dzięki! naprawia wspomniany „problem” chrome i oczywiście możesz mieć inny format wyświetlania we właściwości datetime!
cmxl
Tak, świetne rozwiązanie. Zapewnia to doskonałą obejście dla tych z nas, którzy nie są w USA.
Richard McKenna
Myślę, że to najlepsze rozwiązanie problemu, naprawia tylko problem z edytorem i nie wpływa na istniejące formatowanie ekranu.
dsghi
1
Użycie „Date.cshtml” zamiast „DateTime.cshtml” było magiczną odpowiedzią! Działa również w MVC 4.
Atron Seige,
Wspaniały! Obrigado.
Guilherme de Jesus Santos
16

Jako dodatek do odpowiedzi Darina Dimitrowa:

Jeśli chcesz, aby ta konkretna linia używała określonego (innego niż standardowy) formatu, możesz użyć w MVC5:

@Html.EditorFor(model => model.Property, new {htmlAttributes = new {@Value = @Model.Property.ToString("yyyy-MM-dd"), @class = "customclass" } })
Arjan
źródło
Jak jest @na początku, czy @Value = @Model.Property...nadal tego potrzebujesz @? Masz na myśli tylko new { Value = Model.Property...?
user3454439
11

W MVC 3 musiałem dodać:

using System.ComponentModel.DataAnnotations;

wśród zastosowań podczas dodawania właściwości:

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

Zwłaszcza jeśli dodajesz te właściwości do pliku .edmx, tak jak ja. Odkryłem, że domyślnie pliki .edmx tego nie używają, więc dodawanie tylko proroctw nie wystarczy.

Azoro
źródło
10

Jeśli usuniesz [DataType(DataType.Date)]ze swojego modelu, pole wprowadzania w Chrome zostanie zrenderowane jako type="datetime"i nie będzie też pokazywało datepicker.

bernieb
źródło
Dzięki Bernie. Nie miałem problemu z wyświetleniem selektora, ponieważ nie wprowadzałem danych do pola wprowadzania. Warto to jednak wiedzieć.
Ben Finkel,
Opera renderuje jednak datepicker. Użyj moderatora, by zrobić polifill
klucz wiolinowy
1
Jeśli ma to być data, należy ją wyrenderować jako dane wejściowe typu date. Używanie datetimejako obejścia jest nieodpowiednie, ponieważ nie reprezentuje semantycznie danych.
Chris Pratt
4

Nadal miałem problem z przekazaniem formatu rrrr-MM-dd, ale obejściłem go, zmieniając 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"  })
}
markpcasey
źródło
dziękuję, w końcu to zadziałało, próbowałem string.Format("{0}/{1}/{2}")uzyskać dd/mm/yyyyformat i działa dobrze, użyłem pierwszej metody bazy danych, ale DisplayFormat nie działał z klasą częściową, nie wiem dlaczego ?, w każdym razie ktoś, jeśli to konieczne, wypróbował metodę, nie Próbuję, ale jeśli ktoś potrzebuje, mam nadzieję, że to pomoże
Shaijut,
3

Odpowiedz na MVC4 DataType.Date EditorFor nie wyświetla wartości daty w Chrome, dobrze w IE

W modelu musisz mieć następujący typ deklaracji:

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

LUB

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

Nie musisz używać następującego atrybutu:

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

W pliku Date.cshtml użyj tego szablonu:

@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" })
    } 
}

Baw się dobrze! Pozdrawiam, Blerton

Blerton Hoxha
źródło
Jeśli zrobisz to w ten sposób, Chrome nie da Ci wyboru daty. Korzystam z twojego rozwiązania, ale modyfikuję tak, aby 1) użyłem DisplayFormatatrybutu 2) Zmień test, aby sprawdzić, czy typ przeglądarki to chrome, a następnie wykonaj @Html.EditorFor(m=>m.EstPurchaseDate)3) W przeciwnym razie @Html.TextBox("EstPurchaseDate", dt.ToString("MM/dd/yyyy"))uwaga: na # 2 lepszym sprawdzeniem byłoby, jeśli przeglądarka rozumie HTML5, ale nie wiem jak to zrobić.
David
4
Głosowanie w dół w celu wykrycia przeglądarki w kodzie serwera.
Tetsujin no Oni
1

Jeśli potrzebujesz mieć kontrolę nad formatem daty (innymi słowy, nie tylko format rrrr-mm-dd jest dopuszczalny), innym rozwiązaniem może być dodanie właściwości pomocnika o typie ciągu i dodanie do tej właściwości walidatora daty i powiąż z tą właściwością w interfejsie użytkownika.

    [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");
        }
    }

A oto weryfikator daty:

[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;
    }
}
Martin Staufcik
źródło