Html5 Placeholder dengan .NET MVC 3 Razor EditorUntuk ekstensi?


92

Apakah ada cara untuk menulis placeholder Html5 menggunakan @ Html.EditorFor, atau haruskah saya menggunakan ekstensi TextBoxFor yaitu

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

Atau apakah masuk akal untuk menulis ekstensi khusus kita sendiri yang mungkin dapat menggunakan atribut tampilan 'Deskripsi' melalui DataAnnotations (mirip dengan ini )?

Tentu saja, pertanyaan yang sama juga berlaku untuk 'fokus otomatis'.

Jawaban:


68

Anda dapat melihat artikel berikut untuk menulis kebiasaan DataAnnotationsModelMetadataProvider.

Dan inilah cara lain, ASP.NET MVC 3ish untuk melanjutkan yang melibatkan antarmuka IMetadataAware yang baru diperkenalkan .

Mulailah dengan membuat atribut khusus yang menerapkan antarmuka ini:

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

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

Dan kemudian hiasi model Anda dengannya:

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

Selanjutnya tentukan pengontrol:

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

Tampilan yang sesuai:

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

Dan terakhir template 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>

terima kasih atas info (dan contoh yang bagus) dari antarmuka IMetadataAware!
seekay

4
apakah ini masih berlaku untuk MVC3? Saya melihat [Tampilan (Prompt = "ketik tanda air di sini")] baru di MVC3 tetapi tidak dapat membuatnya berfungsi. ada ide?
smnbss

2
@nbss Anda benar. Lihat jawaban saya untuk melihat bagaimana cara membuatnya Promptbekerja.
Daniel Liuzzi

6
wow, banyak pekerjaan untuk melakukan placeholder? harus menjadi sesuatu yang lebih sederhana: S
krilovich

Ada, lihat beberapa jawaban di bawah ini. Pax punya yang bagus.
Termato

121

Karena komentar smnbs dalam jawaban Darin Dimitrov, Prompttepat untuk tujuan ini, jadi tidak perlu membuat atribut khusus . Dari dokumentasi:

Mendapat atau menyetel nilai yang akan digunakan untuk menyetel tanda air untuk perintah di UI.

Untuk menggunakannya, cukup hiasi properti model tampilan Anda seperti ini:

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

Teks ini kemudian ditempatkan dengan nyaman ModelMetadata.Watermark. Di luar kotak, template default di MVC 3 mengabaikan Watermarkproperti, tetapi membuatnya bekerja sangat sederhana. Yang perlu Anda lakukan adalah mengubah template string default, untuk memberi tahu MVC cara merendernya. Cukup edit String.cshtml, seperti yang dilakukan Darin, kecuali bahwa alih-alih mendapatkan tanda air ModelMetadata.AdditionalValues, Anda mendapatkannya langsung dariModelMetadata.Watermark :

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

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

Dan itu dia.

Seperti yang Anda lihat, kunci untuk membuat semuanya bekerja adalah placeholder = ViewData.ModelMetadata.Watermarksedikit.

Jika Anda juga ingin mengaktifkan watermarking untuk kotak teks multi-baris (textareas), Anda melakukan hal yang sama untuk 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 Memang ada. EditorFor () adalah pembantu template yang diperkenalkan di MVC 2. Sekilas mungkin tampak melakukan hal yang sama seperti TextBox (), tetapi ini memberi Anda keuntungan besar karena memungkinkan Anda untuk mengontrol secara tepat bagaimana Anda ingin HTML Anda dibuat. Jawaban saya didasarkan pada fitur ini untuk "mengajarkan" MVC apa yang harus dilakukan dengan Promptatribut tersebut. Untuk informasi lebih lanjut tentang template ini, Anda dapat merujuk ke posting hebat ini oleh Brad Wilson: bradwilson.typepad.com/blog/2009/10/…
Daniel Liuzzi

2
@DotNetWise Saya tidak yakin mengapa Anda mengatakan itu; semua parameter string DisplayAttribute(termasuk Prompt) dapat dilokalkan. Anda hanya perlu menentukan ResourceType di penjelasan Anda: [Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]. Dan itu dia. Teks watermark sekarang berasal dari kunci AgeGroup di sumber daya PeopleResources .
Daniel Liuzzi

1
Bagaimana jika Anda tidak menggunakan sumber daya .resx tetapi sistem pelokalan .po i18N?
Adaptabi

3
EditorTemplatesFolder @FrancisRodgers secara default tidak ada; Anda hanya membuat di Views\Sharedfolder Anda (atau Views\{ControllerName}jika Anda ingin khusus untuk pengontrol tertentu). Anda kemudian menempatkan Anda menempatkan template .cshtml Anda di dalam folder ini dan Anda siap melakukannya.
Daniel Liuzzi

2
@RobertIvanc Saya telah mengedit jawabannya dan mengembalikan hasil edit yang dibuat oleh Raleigh Buckner yang menyebabkan masalah yang Anda dan Ted laporkan. Terima kasih.
Daniel Liuzzi

22

Saya sebenarnya lebih suka menggunakan nama tampilan untuk teks placeholder sebagian besar waktu. Berikut adalah contoh penggunaan DisplayName:

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

1
Ada permintaan anotasi data khusus untuk tanda air. Dan DisplayName untuk label bidang. Merupakan ide yang buruk untuk mencampurnya. Gunakan hal yang benar untuk tugas yang benar. Lihat jawabanku.
Mike Eshva

1
terima kasih, itulah yang saya cari, sederhana dan langsung ke titik ketika kita bisa mendapatkan nama tampilan lalu mengapa menambahkan lebih banyak kelas
saqibahmad

Ini akan meng-escape ganda teks yang disediakan oleh DisplayName - bukan solusi yang baik misalnya bahasa dengan aksen seperti prancis.
marapet

3

Saya telah menulis kelas yang sederhana:

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

Penggunaannya seperti:

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

Dan properti dalam viewmodel:

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

Perhatikan parameter Prompt. Dalam hal ini saya menggunakan string dari sumber daya untuk pelokalan tetapi Anda dapat menggunakan hanya string, hindari saja parameter ResourceType.


Hanya mendekompilasi metode DisplayNameFor dan membuat analog untuk tanda air.
Mike Eshva

Hai, dapatkah Anda mengubah metode MvcHtmlString WatermarkFor () untuk menggunakan nilai atribut DisplayName jika Tampilan -> Nilai prompt tidak ditentukan?
Sasa Tancev

Di mana Anda menyimpan kelas WatermarkExtension sehingga dapat digunakan seperti yang Anda jelaskan? Html.WatermarkFor (model => model.AddressSuffix)
Craig Gjerdingen

3

Saya menggunakan cara ini dengan file Resource (tidak perlu Prompt lagi!)

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

1

Berikut adalah solusi yang saya buat menggunakan ide-ide di atas yang dapat digunakan untuk TextBoxFor dan 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

Saya pikir membuat EditorTemplate kustom bukanlah solusi yang baik, karena Anda perlu memperhatikan banyak kemungkinan tepmlate untuk berbagai kasus: string, numser, combobox, dan sebagainya. Solusi lainnya adalah ekstensi khusus ke HtmlHelper.

Model:

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

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

}

Tampilan yang sesuai:

@Html.BsEditorFor(x => x.Title)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.