HTML5 Placeholders with.NET MVC 3 Razor Editor for extension?
est-il possible d'écrire le HTML5 placeholder en utilisant @Html.EditorFor, ou devrais-je simplement utiliser la TextBoxFor extension i.e.
@Html.TextBoxFor(model => model.Title, new { @placeholder = "Enter title here"})
ou serait-il logique d'écrire notre propre extension personnalisée qui peut éventuellement utiliser l'attribut display 'Description' via DataAnnotations (similaire à this )?
bien sûr, la même question s'applique à "autofocus".
6 réponses
vous pouvez jeter un oeil à la suivant l'article pour écrire une coutume DataAnnotationsModelMetadataProvider
.
et en voici un autre, plus ASP.NET MVC 3ish façon de procéder 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écorer votre modèle avec elle:
public class MyViewModel
{
[PlaceHolder("Enter title here")]
public string Title { get; set; }
}
définir 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>
comme le commente smnbss dans la réponse de Darin Dimitrov, Prompt
existe précisément dans ce but, il y a donc pas besoin de créer un attribut personnalisé . De la documentation:
Obtient ou définit une valeur qui sera utilisée pour définir la limite pour les invites l'INTERFACE utilisateur.
pour l'utiliser, il suffit de décorer la propriété de votre modèle de vue comme suit:
[Display(Prompt = "numbers only")]
public int Age { get; set; }
This le texte est alors commodément placé dans ModelMetadata.Watermark
. Hors de la boîte, le modèle par défaut dans MVC 3 ignore la propriété Watermark
, mais le faire fonctionner est vraiment simple. Tout ce que vous avez à faire est de modifier le modèle de chaîne par défaut, pour dire à MVC comment le rendre. Juste modifier la Chaîne.cshtml, comme Darin le fait, sauf que plutôt que d'obtenir le filigrane de ModelMetadata.AdditionalValues
, vous l'obtenez directement de ModelMetadata.Watermark
:
~/Views/Shared/Editoremplates / String.cshtml:
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", placeholder = ViewData.ModelMetadata.Watermark })
Et c'est tout.
comme vous pouvez le voir, la clé pour que tout fonctionne est le placeholder = ViewData.ModelMetadata.Watermark
bit.
si vous voulez aussi activer le filigrane pour les boîtes de texte multilignes (textareas), vous faites la même chose 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 })
en fait, je préfère utiliser le nom d'affichage pour le texte du placeholder la plupart du temps. Voici un exemple d'utilisation du DisplayName:
@Html.TextBoxFor(x => x.FirstName, true, null, new { @class = "form-control", placeholder = Html.DisplayNameFor(x => x.FirstName) })
j'ai écrit une classe 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'usage en tant que tel:
@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 Invite de paramètre. Dans ce cas, j'utilise des chaînes de caractères provenant de ressources pour la localisation, mais vous pouvez utiliser juste des chaînes, juste éviter le paramètre ResourceType.
j'utilise cette façon avec le fichier de Ressource (n'a plus besoin D'invite !)
@Html.TextBoxFor(m => m.Name, new
{
@class = "form-control",
placeholder = @Html.DisplayName(@Resource.PleaseTypeName),
autofocus = "autofocus",
required = "required"
})
Voici une solution que j'ai faite en utilisant les idées ci-dessus qui peuvent être utilisés 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));
}
}