web-dev-qa-db-fra.com

Html5 Placeholders avec l'extension .NET MVC 3 Razor EditorFor?

Existe-t-il un moyen d'écrire l'espace réservé Html5 en utilisant @ Html.EditorFor, ou devrais-je simplement utiliser l'extension TextBoxFor i.e.

@Html.TextBoxFor(model => model.Title, new { @placeholder = "Enter title here"})

Ou serait-il judicieux d'écrire notre propre extension personnalisée pouvant éventuellement utiliser l'attribut d'affichage "Description" via DataAnnotations (similaire à this )?

Bien entendu, la même question s’applique également à la «mise au point automatique».

90
seekay

Vous pouvez consulter l'article suivant pour écrire une variable DataAnnotationsModelMetadataProvider personnalisée. 

Et voici une autre façon de procéder, plus ASP.NET MVC 3 impliquant la nouvelle interface IMetadataAware .

Commencez par créer un attribut personnalisé implémentant cette interface:

public class PlaceHolderAttribute : Attribute, IMetadataAware
{
    private readonly string _placeholder;
    public PlaceHolderAttribute(string placeholder)
    {
        _placeholder = placeholder;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["placeholder"] = _placeholder;
    }
}

Et ensuite décorez votre modèle avec:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Définissez ensuite un contrôleur:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }
}

Une vue correspondante:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Title)
    <input type="submit" value="OK" />
}

Et enfin le modèle d'éditeur (~/Views/Shared/EditorTemplates/string.cshtml):

@{
    var placeholder = string.Empty;
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("placeholder"))
    {
        placeholder = ViewData.ModelMetadata.AdditionalValues["placeholder"] as string;
    }
}
<span>
    @Html.Label(ViewData.ModelMetadata.PropertyName)
    @Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { placeholder = placeholder })
</span>
68
Darin Dimitrov

Comme le commentait smnbss dans la réponse de Darin Dimitrov, Prompt existe exactement à cette fin; il existe donc il n'est pas nécessaire de créer un attribut personnalisé}. De la documentation:

Obtient ou définit une valeur qui sera utilisée définir le filigrane pour les invites dans l'interface utilisateur.

Pour l'utiliser, il vous suffit de décorer la propriété de votre modèle de vue de la manière suivante:

[Display(Prompt = "numbers only")]
public int Age { get; set; }

Ce texte est ensuite commodément placé dans ModelMetadata.Watermark. Dans la boîte de dialogue, le modèle par défaut de MVC 3 ignore la propriété Watermark, mais son fonctionnement est très simple. Tout ce que vous avez à faire est d’affiner le modèle de chaîne par défaut pour indiquer à MVC comment le restituer. Editez simplement String.cshtml, comme le fait Darin, à la différence que plutôt que d’obtenir le filigrane de ModelMetadata.AdditionalValues, vous l’obtenez directement de ModelMetadata.Watermark:

~/Views/Shared/EditorTemplates/String.cshtml:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", placeholder = ViewData.ModelMetadata.Watermark })

Et c'est ça.

Comme vous pouvez le constater, la clé pour que tout fonctionne correctement est le bit placeholder = ViewData.ModelMetadata.Watermark.

Si vous souhaitez également activer le filigrane pour les zones de texte multilignes (textareas), vous procédez de la même manière pour MultilineText.cshtml:

~/Views/Shared/EditorTemplates/MultilineText.cshtml:

@Html.TextArea("", ViewData.TemplateInfo.FormattedModelValue.ToString(), 0, 0, new { @class = "text-box multi-line", placeholder = ViewData.ModelMetadata.Watermark })
118
Daniel Liuzzi

En fait, je préfère utiliser le nom d'affichage pour le texte fictif la majorité du temps. Voici un exemple d'utilisation du nom d'affichage:

  @Html.TextBoxFor(x => x.FirstName, true, null, new { @class = "form-control", placeholder = Html.DisplayNameFor(x => x.FirstName) })
22
The Pax Bisonica

J'ai écrit un cours si simple:

public static class WatermarkExtension
{
    public static MvcHtmlString WatermarkFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
        var watermark = ModelMetadata.FromLambdaExpression(expression, html.ViewData).Watermark;
        var htmlEncoded = HttpUtility.HtmlEncode(watermark);
        return new MvcHtmlString(htmlEncoded);
    }
}

L'utilisation en tant que telle:

@Html.TextBoxFor(model => model.AddressSuffix, new {placeholder = Html.WatermarkFor(model => model.AddressSuffix)})

Et la propriété dans un modèle de vue:

[Display(ResourceType = typeof (Resources), Name = "AddressSuffixLabel", Prompt = "AddressSuffixPlaceholder")]
public string AddressSuffix
{
    get { return _album.AddressSuffix; }
    set { _album.AddressSuffix = value; }
}

Avis Paramètre d'invite. Dans ce cas, j'utilise des chaînes de ressources pour la localisation, mais vous pouvez uniquement utiliser des chaînes, il suffit d'éviter le paramètre ResourceType.

3
Mike Eshva

J'utilise de cette façon avec le fichier de ressources (je n'ai plus besoin de prompt!)

@Html.TextBoxFor(m => m.Name, new 
{
     @class = "form-control",
     placeholder = @Html.DisplayName(@Resource.PleaseTypeName),
     autofocus = "autofocus",
     required = "required"
})
3
xicooc

Voici une solution que j'ai faite en utilisant les idées ci-dessus qui peuvent être utilisées pour TextBoxFor et PasswordFor:

public static class HtmlHelperEx
{
    public static MvcHtmlString TextBoxWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        return htmlHelper.TextBoxFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark));

    }

    public static MvcHtmlString PasswordWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        return htmlHelper.PasswordFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark));

    }
}

public static class HtmlAttributesHelper
{
    public static IDictionary<string, object> AddAttribute(this object htmlAttributes, string name, object value)
    {
        var dictionary = htmlAttributes == null ? new Dictionary<string, object>() : htmlAttributes.ToDictionary();
        if (!String.IsNullOrWhiteSpace(name) && value != null && !String.IsNullOrWhiteSpace(value.ToString()))
            dictionary.Add(name, value);
        return dictionary;
    }

    public static IDictionary<string, object> ToDictionary(this object obj)
    {
        return TypeDescriptor.GetProperties(obj)
            .Cast<PropertyDescriptor>()
            .ToDictionary(property => property.Name, property => property.GetValue(obj));
    }
}
1
Vladimir

Je pense que créer un EditorTemplate personnalisé n’est pas une bonne solution, car vous devez vous soucier de nombreux tepmlates possibles pour différents cas: chaînes, numsers, combobox, etc. L’autre solution est une extension personnalisée à HtmlHelper.

Modèle:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Extension d'assistance HTML:

   public static MvcHtmlString BsEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TValue>> expression, string htmlClass = "")
{
    var modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var metadata = modelMetadata;

    var viewData = new
    {
        HtmlAttributes = new
            {
                @class = htmlClass,
                placeholder = metadata.Watermark,
            }
    };
    return htmlHelper.EditorFor(expression, viewData);

}

Une vue correspondante:

@Html.BsEditorFor(x => x.Title)
0
Sel