Segnaposto HTML5 con estensione .NET MVC 3 Razor EditorFor?


92

C'è un modo per scrivere il segnaposto Html5 usando @ Html.EditorFor, o dovrei semplicemente usare l'estensione TextBoxFor cioè

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

Oppure avrebbe senso scrivere la nostra estensione personalizzata che può forse utilizzare l'attributo di visualizzazione "Descrizione" tramite DataAnnotations (simile a questo )?

Ovviamente, la stessa domanda vale anche per "autofocus".

Risposte:


68

Puoi dare un'occhiata al seguente articolo per scrivere un'abitudine DataAnnotationsModelMetadataProvider.

Ed ecco un altro, più ASP.NET MVC 3ish modo di procedere che coinvolge l' interfaccia IMetadataAware di recente introduzione .

Inizia creando un attributo personalizzato che implementa questa interfaccia:

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

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

E poi decora il tuo modello con esso:

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

Quindi definire un controller:

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

Una vista corrispondente:

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

E infine il template dell'editor ( ~/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>

grazie per le informazioni (e un ottimo esempio) dell'interfaccia IMetadataAware!
seekay

4
è ancora valido per MVC3? Ho notato un nuovo [Display (Prompt = "type watermark here")] in MVC3 ma non sono riuscito a farlo funzionare. qualche idea?
smnbss

2
@smnbss Hai ragione. Guarda la mia risposta per vedere come Promptlavorare.
Daniel Liuzzi

6
wow, tanto lavoro per fare un segnaposto? deve essere qualcosa di più semplice: S
krilovich

Ecco, guarda alcune delle risposte qui sotto. La Pax ne ha uno buono.
Termato

121

Come commenta smnbss nella risposta di Darin Dimitrov, Promptesiste esattamente per questo scopo, quindi non è necessario creare un attributo personalizzato . Dalla documentazione:

Ottiene o imposta un valore che verrà usato per impostare la filigrana per i prompt nell'interfaccia utente.

Per usarlo, basta decorare la proprietà del modello di visualizzazione in questo modo:

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

Questo testo viene quindi opportunamente inserito ModelMetadata.Watermark. Per impostazione predefinita, il modello predefinito in MVC 3 ignora la Watermarkproprietà, ma farlo funzionare è davvero semplice. Tutto quello che devi fare è modificare il modello di stringa predefinito, per dire a MVC come renderlo. Basta modificare String.cshtml, come fa Darin, tranne per il fatto che invece di ottenere la filigrana da ModelMetadata.AdditionalValues, la ottieni direttamente da ModelMetadata.Watermark:

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

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

E questo è tutto.

Come puoi vedere, la chiave per far funzionare tutto è il placeholder = ViewData.ModelMetadata.Watermarkbit.

Se desideri abilitare anche la filigrana per le caselle di testo multilinea (aree di testo), fai lo stesso per 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 })

6
@Brett C'è, infatti. EditorFor () è un helper basato su modelli introdotto in MVC 2. A prima vista potrebbe sembrare che faccia la stessa cosa di TextBox (), ma ti dà il grande vantaggio di permetterti di controllare esattamente come vuoi che il tuo HTML venga generato. La mia risposta si basa su questa caratteristica per "insegnare" a MVC cosa fare con l' Promptattributo. Per ulteriori informazioni su questi modelli, puoi fare riferimento a questo fantastico post di Brad Wilson: bradwilson.typepad.com/blog/2009/10/…
Daniel Liuzzi

2
@DotNetWise Non sono sicuro del motivo per cui lo dici; tutti i parametri stringa di DisplayAttribute(incluso Prompt) sono localizzabili. Hai solo bisogno di specificare il ResourceType nella vostra nota: [Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]. E questo è tutto. Il testo della filigrana ora proviene da AgeGroup chiave nella risorsa PeopleResources .
Daniel Liuzzi

1
Cosa succede se non si utilizzano risorse .resx ma il sistema di localizzazione .po i18N?
Adaptabi

3
La EditorTemplatescartella @FrancisRodgers non è presente per impostazione predefinita; crei semplicemente nella tua Views\Sharedcartella (o Views\{ControllerName}se vuoi che sia specifico per un determinato controller). Quindi inserisci i tuoi modelli .cshtml all'interno di questa cartella e dovresti essere a posto.
Daniel Liuzzi

2
@RobertIvanc Ho modificato la risposta e annullato la modifica fatta da Raleigh Buckner che ha causato i problemi segnalati da te e Ted. Grazie.
Daniel Liuzzi

22

In realtà preferisco utilizzare il nome visualizzato per il testo segnaposto la maggior parte delle volte. Ecco un esempio di utilizzo del DisplayName:

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

1
C'è una speciale annotazione dei dati Richiedi una filigrana. E DisplayName è per l'etichetta del campo. È una cattiva idea mescolarli. Usa le cose giuste per i compiti giusti. Guarda la mia risposta.
Mike Eshva

1
grazie, questo è quello che stavo cercando, semplice e al punto in cui possiamo ottenere il nome visualizzato, quindi perché aggiungere più classi
saqibahmad

Questo eseguirà un doppio escape del testo fornito da DisplayName, non una buona soluzione per le lingue ad esempio con accenti come il francese.
marapet

3

Ho scritto una lezione così semplice:

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'utilizzo in quanto tale:

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

E proprietà in un modello di visualizzazione:

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

Avviso parametro Prompt. In questo caso utilizzo stringhe da risorse per la localizzazione ma puoi usare solo stringhe, evita semplicemente il parametro ResourceType.


Ho appena decompilato il metodo DisplayNameFor e creato un analogo per la filigrana.
Mike Eshva

Ciao, puoi cambiare il tuo metodo MvcHtmlString WatermarkFor () per utilizzare il valore dell'attributo DisplayName se Display -> Prompt value non è specificato?
Sasa Tancev

Dove salvi la tua classe WatermarkExtension in modo che possa essere utilizzata come descritto? Html.WatermarkFor (model => model.AddressSuffix)
Craig Gjerdingen

3

Uso in questo modo con il file di risorse (non ho più bisogno di Prompt!)

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

1

Ecco una soluzione che ho realizzato utilizzando le idee sopra che possono essere utilizzate per TextBoxFor e 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));
    }
}

0

Penso che creare un EditorTemplate personalizzato non sia una buona soluzione, perché devi preoccuparti di molti possibili tepmlate per diversi casi: stringhe, numeri, combobox e così via. Un'altra soluzione è l'estensione personalizzata a HtmlHelper.

Modello:

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

Estensione helper 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);

}

Una vista corrispondente:

@Html.BsEditorFor(x => x.Title)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.