Atribut html untuk EditorFor () di ASP.NET MVC

129

Mengapa saya tidak bisa meneruskan atribut html EditorFor()? misalnya;

<%= Html.EditorFor(model => model.Control.PeriodType, 
    new { disabled = "disabled", readonly = "readonly" }) %>

Saya tidak ingin menggunakan metadata

Pembaruan : Solusinya adalah memanggil ini dari tampilan:

 <%=Html.EditorFor( model => model.Control.PeriodEndDate, new {Modifiable=model.Control.PeriodEndDateModifiable})%>

dan digunakan ViewData["Modifiable"]di EditorTemplates / String.ascx kustom saya di mana saya memiliki beberapa logika tampilan yang menentukan apakah akan menambahkan atribut readonly dan / atau dinonaktifkan ke input. Objek anonim yang diteruskan ke EditorFor()dalam parameter yang dipanggil additionalViewDatadan sifat-sifatnya dilewatkan ke template editor di ViewDatakoleksi.

Typo Johnson
sumber
19
Serius, masih di MVC3 batasan ini tidak masuk akal dan itu benar-benar menjengkelkan. Orang-orang di seluruh dunia menghabiskan waktu dan mencabut rambut mereka dengan omong kosong ini. Saya mengirim ini ke Microsoft Connect.
Junior Mayhé
3
Apakah hanya saya, atau apakah itu tampak seperti banyak bs untuk sesuatu yang seharusnya sangat sederhana?
Eric K
Mungkin ini akan membantu Anda: [EditorFor-Implementasi dengan kelas CSS dan atribut HTML] [1] [1]: stackoverflow.com/questions/12675708/…
FunThom
Kemungkinan duplikat properti EditorFor () dan html
Gyrfalcon

Jawaban:

96

EditorForberfungsi dengan metadata, jadi jika Anda ingin menambahkan atribut html Anda selalu bisa melakukannya . Pilihan lain adalah cukup menulis templat khusus dan menggunakan TextBoxFor:

<%= Html.TextBoxFor(model => model.Control.PeriodType, 
    new { disabled = "disabled", @readonly = "readonly" }) %>    
Darin Dimitrov
sumber
Metadata tidak akan berfungsi karena atribut html bervariasi tergantung pada properti lain dalam model, dengan kata lain domain atau logika viemodel harus menentukan atribut html bukan metadata statis. Atau apakah saya melewatkan intinya, dapatkah saya mengatur metadata secara dinamis?
Typo Johnson
Apa PeriodType? Bukankah ini properti sederhana? Jika itu adalah objek yang kompleks, Anda bisa menyesuaikan seluruh templat dengan menempatkan sebagian di ~/Views/ControllerName/EditorTemplates/SomeType.ascxmana SomeTypenama jenis PeriodTypeproperti.
Darin Dimitrov
Juga kode yang Anda sarankan berarti menyerahkan seluruh model ke templat parsial yang mengakses properti tertentu, ini berarti saya memiliki parsial untuk setiap properti?
Typo Johnson
2
Saya mengerti sekarang. Saya dapat menggunakan <% = Html.EditorFor (model => model.Control.PeriodEndDate, new {Modifiable = model.Control.PeriodEndDateModifiable})%> dan menggunakan ViewData ["PeriodEndDateModifiable"] di custom EditorTemplates / String.ascx. Terima kasih
Typo Johnson
1
@ JuniorMayhé, saya tidak akan menyebut ini batasan yang membosankan. Jika Anda berpikir lebih hati-hati, Anda akan memahami bahwa ini masuk akal. Sebenarnya inti dari bantuan EditorFor adalah Anda bisa memiliki templat yang sesuai. Template ini dapat berisi markup apa saja. Belum tentu satu elemen. Masuk akal untuk mendefinisikan @classtemplate editor yang berisi 3 divs misalnya. Helper Html.TextBoxFor memungkinkan Anda untuk mendefinisikan ini karena Anda tahu apa yang dihasilkan helper ini - sebuah kotak teks sehingga masuk akal untuk mendefinisikan kelas ke elemen input.
Darin Dimitrov
115

Pembaruan MVC 5.1 sekarang mendukung pendekatan di bawah ini secara langsung, sehingga berfungsi juga untuk editor bawaan. http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (Ini adalah kasus Great mind thinking atau mereka membaca jawaban saya :)

Akhiri Pembaruan

Jika Anda menggunakan template editor Anda sendiri atau dengan MVC 5.1 yang sekarang mendukung pendekatan di bawah ini langsung untuk editor bawaan.

@Html.EditorFor(modelItem => item.YourProperty, 
  new { htmlAttributes = new { @class="verificationStatusSelect", style = "Width:50px"  } })

kemudian di template Anda (tidak diperlukan untuk tipe sederhana di MVC 5.1)

@Html.TextBoxFor(m => m, ViewData["htmlAttributes"])
AntonK
sumber
5
Fitur baru ini dengan sempurna memecahkan masalah awal yang ditanyakan empat tahun lalu.
CoderSteve
1
Jika alih-alih TextBoxFor dan pembantu seperti itu saya menggunakan banyak template editor khusus, saya tidak akan mengatakan itu ide yang fantastis untuk menambahkan ViewData [...] ke masing-masing ... :(
Alexander
42

Pada MVC 5.1, Anda sekarang dapat melakukan hal berikut:

@Html.EditorFor(model => model, new { htmlAttributes = new { @class = "form-control" }, })

http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features

v hutan
sumber
Tautan di atas sudah mati. Ini tersedia di MVC 5.1, info lebih lanjut di sini: asp.net/mvc/overview/releases/mvc51-release-notes#new-features
Alaa Masoud
1
Terima kasih, saya memperbaiki tautannya juga.
vtforester
2
bagaimana cara menggabungkan htmlAttributes?
Bart Calixto
Ini hanya berfungsi dengan EditorFortemplat bawaan / bawaan . Jika Anda menerapkan sendiri, Anda harus mengikuti jawaban AntonK.
mxmissile
6

Sekarang ASP.Net MVC 5.1 mendapat dukungan bawaan untuknya.

Dari Catatan Rilis

Kami sekarang mengizinkan lewat atribut HTML di EditorFor sebagai objek anonim.

Sebagai contoh:

@Html.EditorFor(model => model, 
              new { htmlAttributes = new { @class = "form-control" }, })
Murali Murugesan
sumber
4

Berikut ini sintaks kode VB.Net untuk atribut html di MVC 5.1 EditorFor

@Html.EditorFor(Function(x) x.myStringProp, New With {.htmlAttributes = New With {.class = "myCssClass", .maxlength="30"}}))
Maks
sumber
3

Kenapa tidak pakai saja

@Html.DisplayFor(model => model.Control.PeriodType)
Mhoque
sumber
30
Salah satu alasannya adalah DisplayFor tidak membuat input, sehingga nilainya hilang pada postback.
LABA
2
Alasan lain adalah skenario khusus di mana editor saat ini-tetapi-tidak-selalu terkunci, dan Anda ingin berkomunikasi bahwa data berpotensi diedit - tidak sekarang.
Mir
2

Jika Anda tidak ingin menggunakan Metadata, Anda dapat menggunakan [UIHint("PeriodType")]atribut untuk menghias properti atau jika ini adalah tipe kompleks, Anda tidak perlu menghias apa pun. EditorFor kemudian akan mencari file PeriodType.aspx atau ascx di folder EditorTemplates dan menggunakannya.

John Farrell
sumber
Terima kasih, saya mungkin akhirnya melakukan itu jika if / else dalam template editor saya hanya diperlukan untuk bidang tertentu
Typo Johnson
Saya pikir Anda mengatakan Anda tidak dapat mengubah model (bukan kode Anda), jadi dekorasi dengan UIHint secara langsung tidak akan menjadi pilihan.
Darrel Lee
2

Saya telah bergulat dengan masalah yang sama hari ini untuk kotak centang yang mengikat bool nullable, dan karena saya tidak dapat mengubah model saya (bukan kode saya) saya harus menemukan cara yang lebih baik untuk menangani ini. Ini agak kasar, tetapi harus bekerja untuk 99% kasus yang mungkin saya temui. Anda jelas harus melakukan beberapa populasi manual dari atribut yang valid untuk setiap jenis input, tapi saya pikir saya sudah mendapatkan semuanya untuk kotak centang.

Dalam template editor Boolean.cshtml saya:

@model bool?

@{
    var attribs = new Dictionary<string, object>();
    var validAttribs = new string[] {"style", "class", "checked", "@class",
        "classname","id", "required", "value", "disabled", "readonly", 
        "accesskey", "lang", "tabindex", "title", "onblur", "onfocus", 
        "onclick", "onchange", "ondblclick", "onmousedown", "onmousemove", 
        "onmouseout", "onmouseover", "onmouseup", "onselect"};
    foreach (var item in ViewData) 
    {
        if (item.Key.ToLower().IndexOf("data_") == 0 || item.Key.ToLower().IndexOf("aria_") == 0) 
        {
            attribs.Add(item.Key.Replace('_', '-'), item.Value);
        } 
        else 
        {
            if (validAttribs.Contains(item.Key.ToLower()))
            {
                attribs.Add(item.Key, item.Value);
            }
        }
    }
}

@Html.CheckBox("", Model.GetValueOrDefault(), attribs)
Isoron
sumber
Saya menambahkan Dictionary<string,string> attribs = new Dictionary<string,string>();dan attribs.Add("tabindex","16");di salah satu @( )blok di bagian atas halaman saya. Kemudian saya lakukan @Html.CheckBox("IsActive", Model.IsActive.HasValue ? Model.IsActive : false, attribs)di halaman saya dan itu memberi saya kesalahan: "'System.Web.Mvc.HtmlHelper <MyProject.Models.MyObject>' tidak mengandung definisi untuk 'Kotak Centang' dan metode ekstensi terbaik overload 'System.Web. Mvc.InputExtensions.CheckBox (System.Web.Mvc.HtmlHelper, string.bool, objek) 'memiliki beberapa argumen yang tidak valid ".
vapcguy
2

Anda masih dapat menggunakan EditorFor. Cukup berikan atribut style / html mana saja sebagai ViewData.

@Html.EditorFor(model => model.YourProperty, new { style = "Width:50px" })

Karena EditorFor menggunakan templat untuk merender, Anda bisa mengganti templat default untuk properti Anda dan cukup meneruskan atribut style sebagai ViewData.

Jadi EditorTemplate Anda ingin yang berikut:

@inherits System.Web.Mvc.WebViewPage<object>

@Html.TextBoxFor(m => m, new { @class = "text ui-widget-content", style=ViewData["style"] })

sumber
1
Html.TextBoxFor(model => model.Control.PeriodType, 
    new { @class="text-box single-line"})

Anda bisa menggunakan seperti ini; output yang sama dengan Html.EditorFor, dan Anda dapat menambahkan atribut html Anda

zamoldar
sumber
Kecuali TextBoxFormengabaikan jenis apa pun DisplayFormatyang mungkin Anda coba terapkan.
Eric K
1

Cukup buat template Anda sendiri untuk jenis di Views / Shared / EditorTemplates / MyTypeEditor.vbhtml

@ModelType MyType

@ModelType MyType
@Code
    Dim name As String = ViewData("ControlId")
    If String.IsNullOrEmpty(name) Then
        name = "MyTypeEditor"
    End If
End Code

' Mark-up for MyType Editor
@Html.TextBox(name, Model, New With {.style = "width:65px;background-color:yellow"})

Aktifkan editor dari tampilan Anda dengan properti model:

@Html.EditorFor(Function(m) m.MyTypeProperty, "MyTypeEditor", New {.ControlId = "uniqueId"})

Maafkan sintaks VB. Itulah cara kami menggulung.

Darrel Lee
sumber
1

Dalam kasus saya, saya mencoba membuat template editor input angka HTML5 yang dapat menerima atribut tambahan. Pendekatan yang lebih rapi adalah menulis HTML Helper Anda sendiri, tetapi karena saya sudah memiliki template .ascx, saya menggunakan pendekatan ini:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<input id="<%= Regex.Replace(ViewData.TemplateInfo.GetFullHtmlFieldId(""), @"[\[\]]", "_") %>" name="<%= ViewData.TemplateInfo.HtmlFieldPrefix %>" type="number" value="<%= ViewData.TemplateInfo.FormattedModelValue %>"
<% if (ViewData["attributes"] != null)
   {
       Dictionary<string, string> attributes = (Dictionary<string, string>)ViewData["attributes"];
       foreach (string attributeName in attributes.Keys){%>
        <%= String.Format(" {0}=\"{1}\"", attributeName, attributes[attributeName])%>
       <% }
   } %> />

Bit jelek ini menciptakan input tipe angka dan mencari Kamus ViewData dengan kunci "atribut". Itu akan beralih melalui kamus menambahkan pasangan kunci / nilainya sebagai atribut. Regex dalam atribut ID tidak terkait dan ada karena ketika digunakan dalam koleksi, GetFullHtmlFieldId()mengembalikan id yang berisi tanda kurung siku []yang biasanya akan dilepaskan sebagai garis bawah.

Template ini kemudian disebut seperti ini:

Html.EditorFor(m => m.Quantity, "NumberField", new { attributes = new Dictionary<string, string>() { { "class", "txtQuantity" } } }

Verbose, tetapi berhasil. Anda mungkin bisa menggunakan refleksi dalam templat untuk menggunakan nama properti sebagai nama atribut alih-alih menggunakan kamus.

xr280xr
sumber
1

Atur kondisi menggunakan ViewDatadi controller

ViewData["Modifiable"] = model.recProcessed;

Kemudian gunakan viewdata ini dalam template editor untuk mengatur atribut html kontrol

@Html.RadioButton(prefix, li.Value, li.Selected, @ViewData["Modifiable"].ToString().ToLower() == "true" ? (object)new  { @id = li.Value, @disabled = "disabled" } : new { @id = li.Value })
reine varghese
sumber
0

MVC 5.1 dan solusi yang lebih tinggi (akan menggabungkan HtmlAttributes lokal dan didefinisikan dalam EditorTemplates):

Shared \ EditorTemplates \ String.cshtml:

@Html.TextBoxFor(model => model, new { @class = "form-control", placeholder = ViewData.ModelMetadata.Watermark }.ToExpando().MergeHtmlAttributes(ViewData["htmlAttributes"].ToExpando()))

Ekstensi:

public static IDictionary<string, object> MergeHtmlAttributes(this ExpandoObject source1, dynamic source2)
{
    Condition.Requires(source1, "source1").IsNotNull().IsLongerThan(0);

    IDictionary<string, object> result = source2 == null
        ? new Dictionary<string, object>()
        : (IDictionary<string, object>) source2;

    var dictionary1 = (IDictionary<string, object>) source1;

    string[] commonKeys = result.Keys.Where(dictionary1.ContainsKey).ToArray();
    foreach (var key in commonKeys)
    {
        result[key] = string.Format("{0} {1}", dictionary1[key], result[key]);
    }

    foreach (var item in dictionary1.Where(pair => !result.ContainsKey(pair.Key)))
    {
        result.Add(item);
    }

    return result;
}

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var item in anonymousDictionary)
        expando.Add(item);
    return (ExpandoObject)expando;
}

public static bool HasProperty(this ExpandoObject expando, string key)
{
    return ((IDictionary<string, object>)expando).ContainsKey(key);
}

Pemakaian:

@Html.EditorFor(m => m.PromotionalCode, new { htmlAttributes = new { ng_model = "roomCtrl.searchRoomModel().promoCode" }})
Sergey G.
sumber
1
Terima kasih, itu berhasil. Kecuali untuk semua atribut data_xxx, di mana saya harus mengganti _ dengan - saat casting source1dan source2sebagai IDictionary<string, object>. Saya membuat fungsi ini: private static IDictionary<string, object> ToHtmlAttributesDictionary(this IEnumerable<KeyValuePair<string, object>> dico) { return dico.ToDictionary(s => s.Key.Replace('_', '-'), s => s.Value); }
Marien Monnier