HTML5-Platzhalter mit .NET MVC 3 Razor EditorFür die Erweiterung?


92

Gibt es eine Möglichkeit, den Html5-Platzhalter mit @ Html.EditorFor zu schreiben , oder sollte ich nur die TextBoxFor-Erweiterung verwenden, d. H.

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

Oder wäre es sinnvoll , unsere eigene Erweiterung zu schreiben , die vielleicht die ‚Beschreibung‘ Anzeigeattribut über DataAnnotations (ähnlich verwenden diese )?

Die gleiche Frage gilt natürlich auch für den Autofokus.

Antworten:


68

Sie können den folgenden Artikel lesen, um eine benutzerdefinierte zu schreiben DataAnnotationsModelMetadataProvider.

Und hier ist eine weitere, mehr ASP.NET MVC 3ish-Methode, um mit der neu eingeführten IMetadataAware- Schnittstelle fortzufahren .

Erstellen Sie zunächst ein benutzerdefiniertes Attribut, das diese Schnittstelle implementiert:

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

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

Und dann dekorieren Sie Ihr Modell damit:

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

Definieren Sie als Nächstes eine Steuerung:

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

Eine entsprechende Ansicht:

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

Und zum Schluss die Editor-Vorlage ( ~/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>

Vielen Dank für die Informationen (und ein gutes Beispiel) über die IMetadataAware-Oberfläche!
Sequestay

4
Ist dies noch gültig für MVC3? Ich habe in MVC3 ein neues [Display (Prompt = "Typ Wasserzeichen hier")] bemerkt, konnte es aber nicht zum Laufen bringen. irgendeine Idee?
smnbss

2
@smnbss Du bist richtig. Sehen Sie meine Antwort, um zu sehen, wie man PromptArbeit macht.
Daniel Liuzzi

6
wow so viel Arbeit für einen Platzhalter? muss etwas einfacher sein: S
krilovich

Schauen Sie sich einige der folgenden Antworten an. Der Pax hat einen guten.
Termato

121

Da smnbss-Kommentare in Darin Dimitrovs Antwort Promptgenau zu diesem Zweck vorhanden sind, muss kein benutzerdefiniertes Attribut erstellt werden . Aus der Dokumentation:

Ruft einen Wert ab oder legt einen Wert fest, mit dem das Wasserzeichen für Eingabeaufforderungen in der Benutzeroberfläche festgelegt wird.

Um es zu verwenden, dekorieren Sie einfach die Eigenschaft Ihres Ansichtsmodells wie folgt:

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

Dieser Text wird dann bequem in platziert ModelMetadata.Watermark. Standardmäßig ignoriert die Standardvorlage in MVC 3 die WatermarkEigenschaft, aber es ist wirklich einfach, sie zum Laufen zu bringen. Sie müssen lediglich die Standardzeichenfolgenvorlage anpassen, um MVC mitzuteilen, wie sie gerendert werden soll. Bearbeiten Sie einfach String.cshtml, wie es Darin tut, außer dass Sie das Wasserzeichen nicht ModelMetadata.AdditionalValueserhalten, sondern direkt von ModelMetadata.Watermark:

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

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

Und das ist alles.

Wie Sie sehen können, ist der Schlüssel, damit alles funktioniert, das placeholder = ViewData.ModelMetadata.WatermarkBit.

Wenn Sie das Wasserzeichen auch für mehrzeilige Textfelder (Textbereiche) aktivieren möchten, tun Sie dasselbe für 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 gibt es in der Tat. EditorFor () ist ein in MVC 2 eingeführter Vorlagen- Helfer. Auf den ersten Blick scheint er dasselbe zu tun wie TextBox (), bietet Ihnen jedoch den großen Vorteil, dass Sie genau steuern können, wie Ihr HTML generiert werden soll. Meine Antwort basiert auf dieser Funktion, um MVC "beizubringen", was mit dem PromptAttribut zu tun ist . Weitere Informationen zu diesen Vorlagen finden Sie in diesem großartigen Beitrag von Brad Wilson: bradwilson.typepad.com/blog/2009/10/…
Daniel Liuzzi

2
@DotNetWise Ich bin mir nicht sicher, warum du das sagst; Alle Zeichenfolgenparameter von DisplayAttribute(einschließlich Eingabeaufforderung) sind lokalisierbar. Sie müssen nur den Ressourcentyp in Ihrer Anmerkung angeben : [Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]. Und das ist es. Wasserzeichentext stammt jetzt von der wichtigsten AgeGroup in der Ressource PeopleResources .
Daniel Liuzzi

1
Was ist, wenn Sie keine .resx-Ressourcen, sondern ein i18N .po-Lokalisierungssystem verwenden?
Adaptabi

3
Der EditorTemplatesOrdner @FrancisRodgers ist standardmäßig nicht vorhanden. Sie erstellen nur in Ihrem Views\SharedOrdner (oder Views\{ControllerName}wenn Sie möchten, dass es für einen bestimmten Controller spezifisch ist). Sie platzieren dann Ihre .cshtml-Vorlagen in diesem Ordner und Sie sollten bereit sein, loszulegen.
Daniel Liuzzi

2
@RobertIvanc Ich habe die Antwort bearbeitet und die von Raleigh Buckner vorgenommene Bearbeitung zurückgesetzt, die die von Ihnen und Ted gemeldeten Probleme verursacht. Vielen Dank.
Daniel Liuzzi

22

Eigentlich bevorzuge ich es, den Anzeigenamen die meiste Zeit für den Platzhaltertext zu verwenden. Hier ist ein Beispiel für die Verwendung des Anzeigenamens:

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

1
Es gibt eine spezielle Eingabeaufforderung für Datenanmerkungen für ein Wasserzeichen. Und DisplayName steht für Feldbezeichnung. Es ist eine schlechte Idee, sie zu mischen. Verwenden Sie die richtigen Dinge für die richtigen Aufgaben. Schau dir meine Antwort an.
Mike Eshva

1
danke, das ist es, wonach ich gesucht habe, einfach und bis zu dem Punkt, an dem wir den Anzeigenamen bekommen können, warum dann weitere Klassen hinzufügen
saqibahmad

Dadurch wird der von DisplayName bereitgestellte Text doppelt umgangen - keine gute Lösung, beispielsweise für Sprachen mit Akzenten wie Französisch.
Marapet

3

Ich habe eine so einfache Klasse geschrieben:

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

Die Verwendung als solche:

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

Und Eigentum in einem Ansichtsmodell:

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

Beachten Sie den Eingabeaufforderungsparameter. In diesem Fall verwende ich Zeichenfolgen aus Ressourcen zur Lokalisierung, aber Sie können nur Zeichenfolgen verwenden. Vermeiden Sie einfach den Parameter ResourceType.


Einfach die DisplayNameFor-Methode dekompiliert und ein Analogon für das Wasserzeichen erstellt.
Mike Eshva

Hallo, können Sie bitte Ihre Methode MvcHtmlString WatermarkFor () so ändern, dass der Attributwert DisplayName verwendet wird, wenn Anzeige -> Eingabeaufforderungswert nicht angegeben ist?
Sasa Tancev

Wo speichern Sie Ihre WatermarkExtension-Klasse, damit sie dann wie beschrieben verwendet werden kann? Html.WatermarkFor (model => model.AddressSuffix)
Craig Gjerdingen

3

Ich benutze diesen Weg mit der Ressourcendatei (brauche keine Eingabeaufforderung mehr!)

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

1

Hier ist eine Lösung, die ich mit den oben genannten Ideen gemacht habe, die für TextBoxFor und PasswordFor verwendet werden können:

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

Ich denke, ein benutzerdefiniertes EditorTemplate zu erstellen ist keine gute Lösung, da Sie sich um viele mögliche Tepmlates für verschiedene Fälle kümmern müssen: Zeichenfolgen, Nummern, Kombinationsfelder und so weiter. Eine andere Lösung ist die benutzerdefinierte Erweiterung von HtmlHelper.

Modell:

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

HTML-Helfer-Erweiterung:

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

}}

Eine entsprechende Ansicht:

@Html.BsEditorFor(x => x.Title)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.