MVC4 DataType.Date EditorFor n'affichera pas la valeur de date dans Chrome, très bien dans Internet Explorer

198

J'utilise l'attribut DataType.Date sur mon modèle et un EditorFor à mon avis. Cela fonctionne bien dans Internet Explorer 8 et Internet Explorer 9 , mais dans Google Chrome, il affiche un sélecteur de date et au lieu d'afficher la valeur, il affiche simplement "Mois / Jour / Année" en texte gris délavé.

Pourquoi Google Chrome n'affiche-t-il pas la valeur?

Modèle:

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

Vue:

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

Chrome

Internet Explorer

Ben Finkel
la source

Réponses:

377

Lorsque vous décorez une propriété de modèle avec [DataType(DataType.Date)]le modèle par défaut dans ASP.NET MVC 4 génère un champ d'entrée 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" />

Les navigateurs prenant en charge HTML5 tels que Google Chrome affichent ce champ de saisie avec un sélecteur de date.

Pour afficher correctement la date, la valeur doit être formatée en tant que 2012-09-28. Citation de la spécification :

valeur: une date complète valide telle que définie dans [RFC 3339], avec la qualification supplémentaire que le composant année est composé de quatre chiffres ou plus représentant un nombre supérieur à 0.

Vous pouvez appliquer ce format en utilisant l' DisplayFormatattribut:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }
Darin Dimitrov
la source
44
Merci Darin, c'était parfait! Vous avez répondu à tant de mes questions MVC au cours des deux dernières années, vous rock!
Ben Finkel
3
Excellente réponse, mais je pense que cela est attrayant, vous devez le forcer juste pour que le contrôle fonctionne correctement!
Coops
7
Quelle serait la manière de procéder "globalement" pour toutes les propriétés marquées [DataType(DataType.Date)]pour ne pas avoir à marquer toutes ces propriétés séparément avec le risque d'en manquer?
Marjan Venema
7
Darin, que pouvons-nous faire en dehors des États-Unis? Comment puis-je définir la valeur de spécification mais afficher un format de date personnalisé? c'est-à-dire au Royaume-Uni?
Piotr Kula
3
@ MarjanVenema- J'ai utilisé le "ExtensibleModelMetadataProvider" du FailTracker de Matt Honeycutt ( github.com/MattHoneycutt/Fail-Tracker ). Regardez sous le dossier Infrastructure pour les ModelMetadata. J'ai utilisé ces classes, puis créé une implémentation de filtre de IModelMetadataFilter. Lorsque la méthode TransformMetadata est appelée, vous pouvez ensuite modifier les propriétés "DisplayFormatString" et "EditFormatString" des métadonnées. J'espère que cela vous amènera dans la bonne direction (btw, il y a une excellente vidéo pluridisciplinaire qui utilise Fail-Tracker)
SwampyFox
44

Dans MVC5.2, ajoutez Date.cshtml au dossier ~ / 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
la source
Merci! corrige le "problème" de chrome mentionné et bien sûr, vous pouvez avoir un autre format d'affichage sur votre propriété datetime!
cmxl
Oui excellente solution. Cela fournit un excellent travail pour ceux d'entre nous qui ne sont pas aux États-Unis.
Richard McKenna
Je pense que c'est la meilleure solution au problème, il résout uniquement le problème de l'éditeur et n'affecte pas le formatage d'affichage existant.
dsghi
1
Utiliser "Date.cshtml" au lieu de "DateTime.cshtml" était la réponse magique! Cela fonctionne également dans MVC 4.
Atron Seige
Génial! Obrigado.
Guilherme de Jesus Santos
16

En complément de la réponse de Darin Dimitrov:

Si vous souhaitez que cette ligne particulière utilise un certain format (différent du format standard), vous pouvez utiliser dans MVC5:

@Html.EditorFor(model => model.Property, new {htmlAttributes = new {@Value = @Model.Property.ToString("yyyy-MM-dd"), @class = "customclass" } })
Arjan
la source
Comme il y @en a au début, ça a @Value = @Model.Property...encore besoin de ça @? Voulez-vous dire juste new { Value = Model.Property...?
user3454439
11

Dans MVC 3, j'ai dû ajouter:

using System.ComponentModel.DataAnnotations;

parmi les utilisations lors de l'ajout de propriétés:

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

Surtout si vous ajoutez ces propriétés dans un fichier .edmx comme moi. J'ai trouvé que par défaut les fichiers .edmx ne l'ont pas en utilisant donc ajouter seulement des propriétés n'est pas suffisant.

Azoro
la source
10

Si vous supprimez [DataType(DataType.Date)]de votre modèle, le champ de saisie dans Chrome est rendu comme type="datetime"et n'affichera pas non plus le sélecteur de date.

bernieb
la source
Merci Bernie. Je n'étais pas si mal avec le sélecteur qui apparaissait comme je l'étais avec les données qui n'étaient pas mises dans la zone de saisie. C'est bon à savoir cependant.
Ben Finkel
Opera rend cependant un sélecteur de date. Utilisez modernizr pour faire du polyfill
cleftheris
1
Si c'est censé être une date, elle doit être rendue comme une entrée de type date. L'utilisation datetimecomme solution de contournement est inappropriée, car elle ne représente pas sémantiquement les données.
Chris Pratt
4

J'ai toujours eu un problème avec le passage du format aaaa-MM-jj, mais je l'ai contourné en modifiant le 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
la source
merci enfin cela a fonctionné, j'ai essayé string.Format("{0}/{1}/{2}")d'obtenir le dd/mm/yyyyformat, et cela fonctionne très bien, j'ai utilisé la première méthode de base de données mais DisplayFormat n'a pas fonctionné avec une classe partielle, je ne sais pas pourquoi ?, de toute façon, si nécessaire, essayez cette méthode, je n'ai pas t essayer mais si quelqu'un avait besoin, j'espère que cela aide
shaijut
3

Répondre à MVC4 DataType.Date EditorFor n'affichera pas la valeur de date dans Chrome, très bien dans IE

Dans le modèle, vous devez avoir le type de déclaration suivant:

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

OU

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

Vous n'avez pas besoin d'utiliser l'attribut suivant:

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

Au Date.cshtml utilisez ce modèle:

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

S'amuser! Cordialement, Blerton

Blerton Hoxha
la source
Si vous le faites de cette façon, Chrome ne vous fournira pas de sélecteur de date. J'utilise votre solution, mais je la modifie de manière à ce que 1) j'utilise l' DisplayFormatattribut 2) changez le test pour vérifier si le type de navigateur est chrome, puis faites @Html.EditorFor(m=>m.EstPurchaseDate)3) Sinon faites @Html.TextBox("EstPurchaseDate", dt.ToString("MM/dd/yyyy"))Remarque: sur # 2, une meilleure vérification serait si le navigateur comprend HTML5, mais je ne sais pas comment faire.
David
4
Vote en aval pour la détection du navigateur dans le code côté serveur.
Tetsujin no Oni
1

Si vous avez besoin de contrôler le format de la date (en d'autres termes, pas seulement le format aaaa-mm-jj est acceptable), une autre solution pourrait être d'ajouter une propriété d'assistance de type chaîne et d'ajouter un validateur de date à cette propriété et liez à cette propriété sur l'interface utilisateur.

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

Et voici un validateur de date:

[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
la source