O MVC4 DataType.Date EditorFor não exibirá o valor da data no Chrome, mas no Internet Explorer

198

Estou usando o atributo DataType.Date no meu modelo e um EditorFor no meu modo de exibição. Isso está funcionando bem no Internet Explorer 8 e no Internet Explorer 9 , mas no Google Chrome está mostrando um seletor de datas e, em vez de exibir o valor, apenas exibe "Mês / Dia / Ano" em texto cinza desbotado.

Por que o Google Chrome não exibe o valor?

Modelo:

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

Visão:

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

cromada

Internet Explorer

Ben Finkel
fonte

Respostas:

377

Quando você decora uma propriedade de modelo com [DataType(DataType.Date)]o modelo padrão no ASP.NET MVC 4, gera um campo de entrada de 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" />

Os navegadores que suportam HTML5, como o Google Chrome, processam esse campo de entrada com um seletor de datas.

Para exibir corretamente a data, o valor deve ser formatado como 2012-09-28. Citação da especificação :

valor: uma data completa válida, conforme definido na [RFC 3339], com a qualificação adicional de que o componente do ano é de quatro ou mais dígitos, representando um número maior que 0.

Você pode aplicar esse formato usando o DisplayFormatatributo:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }
Darin Dimitrov
fonte
44
Darin obrigado, isso foi perfeito! Você respondeu a muitas das minhas perguntas sobre MVC nos últimos dois anos, você é demais!
precisa
3
Ótima resposta, mas acho que isso é atraente, você precisa forçá-lo apenas para que o controle funcione corretamente!
Coops
7
Qual seria a maneira de fazer isso "globalmente" para todas as propriedades marcadas [DataType(DataType.Date)]para que eu não tivesse que marcar todas essas propriedades separadamente com o risco de perder algumas?
Marjan Venema
7
Darin, o que nós, pessoas fora dos EUA, podemos fazer? Como posso definir o valor da especificação, mas exibir um formato de data personalizado? ou seja, Reino Unido?
Piotr Kula
3
@ MarjanVenema- Eu usei o "ExtensibleModelMetadataProvider" do FailTracker de Matt Honeycutt ( github.com/MattHoneycutt/Fail-Tracker ). Procure na pasta Infraestrutura os ModelMetadata. Eu usei essas classes e criei uma implementação de filtro do IModelMetadataFilter. Quando o método TransformMetadata é chamado, você pode editar as propriedades "DisplayFormatString" e "EditFormatString" dos metadados. Espero que isso faz com que você na direção certa (aliás, há um grande vídeo pluralsight que usa Fail-Tracker)
SwampyFox
44

No MVC5.2, adicione Date.cshtml à pasta ~ / 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
fonte
obrigado! corrige o "problema" mencionado do chrome e, é claro, você pode ter outro formato de exibição em sua propriedade datetime!
Cmxl
Sim, ótima solução. Isso fornece uma excelente solução para aqueles que não estão nos EUA.
Richard McKenna
Penso que esta é a melhor solução para o problema, corrige apenas o problema do editor e não afeta a formatação de exibição existente.
precisa saber é o seguinte
1
Usar "Date.cshtml" em vez de "DateTime.cshtml" foi a resposta mágica! Também funciona no MVC 4.
Atron Seige 22/10/2015
Ótimo! Obrigado.
Guilherme de Jesus Santos
16

Como complemento à resposta de Darin Dimitrov:

Se você deseja que apenas essa linha em particular use um determinado formato (diferente do padrão), é possível usar no MVC5:

@Html.EditorFor(model => model.Property, new {htmlAttributes = new {@Value = @Model.Property.ToString("yyyy-MM-dd"), @class = "customclass" } })
Arjan
fonte
Como existe @no começo, isso @Value = @Model.Property...ainda precisa disso @? Você quer dizer apenas new { Value = Model.Property...?
user3454439
11

No MVC 3, tive que adicionar:

using System.ComponentModel.DataAnnotations;

entre usos ao adicionar propriedades:

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

Especialmente se você estiver adicionando essas propriedades no arquivo .edmx como eu. Descobri que, por padrão, os arquivos .edmx não possuem esse recurso, portanto, adicionar apenas propriedades não é suficiente.

Azoro
fonte
10

Se você remover [DataType(DataType.Date)]do seu modelo, o campo de entrada no Chrome será renderizado como type="datetime"e também não mostrará o selecionador de data.

Bernieb
fonte
Obrigado Bernie. Não tive tanto problema com o seletor aparecendo quanto com os dados não sendo colocados na caixa de entrada. É bom saber isso.
Ben Finkel
O Opera renderiza um datepicker. Use Modernizr fazer alguma polyfill
cleftheris
1
Se é para ser uma data, deve ser renderizada como uma entrada do tipo date. Usar datetimecomo solução alternativa é inadequado, pois ele não representa os dados semântica.
Chris Pratt
4

Eu ainda tinha um problema ao passar o formato aaaa-MM-dd, mas resolvi alterando o 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
fonte
obrigado, finalmente, isso funcionou, eu tentei string.Format("{0}/{1}/{2}")obter dd/mm/yyyyo formato, e funciona bem, eu usei banco de dados primeiro método, mas DisplayFormat não trabalhou com classe parcial, não sei por quê ?, qualquer um de qualquer maneira, se necessário tentar este método, eu não' t tentar, mas se alguém necessário, espero que ajude
shaijut
3

O MVC4 DataType.Date EditorFor não exibirá o valor da data no Chrome, mas no IE

No modelo, você precisa ter o seguinte tipo de declaração:

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

OU

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

Você não precisa usar o seguinte atributo:

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

No Date.cshtml, use este modelo:

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

Diverta-se! Atenciosamente, Blerton

Blerton Hoxha
fonte
Se você fizer dessa maneira, o Chrome não fornecerá um selecionador de data. Estou usando sua solução, mas modificando para que 1) Eu use o DisplayFormatatributo 2) Altere o teste para verificar se o tipo de navegador é chrome, e faça @Html.EditorFor(m=>m.EstPurchaseDate)3) Outra @Html.TextBox("EstPurchaseDate", dt.ToString("MM/dd/yyyy"))Nota: no # 2, uma verificação melhor seria se o navegador entende HTML5, mas não sei como fazer isso.
David
4
Voto negativo para detecção do navegador no código do lado do servidor.
Tetsujin no Oni
1

Se você precisar ter controle sobre o formato da data (em outras palavras, não apenas o formato aaaa-mm-dd é aceitável), outra solução poderia ser adicionar uma propriedade auxiliar do tipo string e adicionar um validador de data a essa propriedade e vincule a essa propriedade na interface do usuário.

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

E aqui está um validador de data:

[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
fonte