แอตทริบิวต์ Html สำหรับ EditorFor () ใน ASP.NET MVC


129

ทำไมฉันจึงไม่สามารถผ่านใน html แอตทริบิวต์EditorFor()? เช่น;

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

ฉันไม่ต้องการใช้ข้อมูลเมตา

อัปเดต : วิธีแก้ปัญหาคือการเรียกสิ่งนี้จากมุมมอง:

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

และใช้ViewData["Modifiable"]ใน EditorTemplates / String.ascx ที่กำหนดเองของฉันโดยที่ฉันมีตรรกะมุมมองบางอย่างที่กำหนดว่าจะเพิ่มแอตทริบิวต์แบบอ่านอย่างเดียวและ / หรือปิดใช้งานให้กับอินพุตหรือไม่วัตถุที่ไม่ระบุชื่อที่ส่งผ่านเข้าไปEditorFor()เป็นพารามิเตอร์ที่เรียกadditionalViewDataและคุณสมบัติของมันจะถูกส่งไปยังเทมเพลตเอดิเตอร์ในViewDataชุด


19
อย่างจริงจังยังคงอยู่ใน MVC3 ข้อ จำกัด นี้ไม่มีเหตุผลและมันน่ารำคาญจริงๆ ผู้คนทั่วโลกกำลังใช้เวลากับการดึงผมออกไปกับเรื่องไร้สาระนี้ ฉันกำลังส่งสิ่งนี้ไปยัง Microsoft Connect
Junior Mayhé


3
มันเป็นแค่ฉันหรือว่ามันดูเหมือน bs มากสำหรับบางสิ่งที่ควรจะง่ายมาก?
Eric K

บางทีนี่อาจช่วยคุณได้: [EditorFor-Implementation with CSS คลาสและแอตทริบิวต์ HTML] [1] [1]: stackoverflow.com/questions/12675708/…
FunThom

คำตอบ:


96

EditorForผลงานกับเมตาดาต้าดังนั้นหากคุณต้องการที่จะเพิ่มคุณลักษณะ html ที่คุณก็สามารถทำมันได้ อีกทางเลือกหนึ่งคือเพียงแค่เขียนเทมเพลตที่กำหนดเองและใช้TextBoxFor:

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

ข้อมูลเมตาจะไม่ทำงานเนื่องจากแอตทริบิวต์ html แตกต่างกันไปขึ้นอยู่กับคุณสมบัติอื่น ๆ ในโมเดลกล่าวอีกนัยหนึ่งคือโดเมนหรือตรรกะของ viemodel ควรกำหนดแอตทริบิวต์ html ไม่ใช่ข้อมูลเมตาแบบคงที่ หรือฉันไม่เข้าใจฉันสามารถตั้งค่าข้อมูลเมตาแบบไดนามิกได้หรือไม่
Typo Johnson

คืออะไรPeriodType? มันไม่ใช่คุณสมบัติง่ายๆ? หากเป็นวัตถุที่ซับซ้อนคุณสามารถปรับแต่งเทมเพลตทั้งหมดได้โดยการวางบางส่วนใน~/Views/ControllerName/EditorTemplates/SomeType.ascxตำแหน่งที่SomeTypeเป็นชื่อประเภทของPeriodTypeคุณสมบัติ
Darin Dimitrov

นอกจากนี้รหัสที่แนะนำของคุณยังหมายถึงการส่งแบบจำลองทั้งหมดไปยังเทมเพลตบางส่วนซึ่งเข้าถึงคุณสมบัติเฉพาะซึ่งหมายความว่าฉันมีบางส่วนสำหรับแต่ละคุณสมบัติหรือไม่
Typo Johnson

2
ฉันเข้าใจคุณแล้ว ฉันสามารถใช้ <% = Html.EditorFor (model => model.Control.PeriodEndDate, new {Modifiable = model.Control.PeriodEndDateModifiable})%> และใช้ ViewData ["PeriodEndDateModifiable"] ใน EditorTemplates / String.ascx ที่กำหนดเองของฉัน ขอบคุณ
Typo Johnson

1
@ JuniorMayhéฉันจะไม่เรียกสิ่งนี้ว่าเป็นข้อ จำกัด ที่น่าเบื่อ หากคุณคิดอย่างรอบคอบมากขึ้นคุณจะเข้าใจว่าสิ่งนี้สมเหตุสมผล ในความเป็นจริงจุดรวมของ EditorFor helper คือคุณสามารถมีเทมเพลตที่เกี่ยวข้องได้ เทมเพลตนี้อาจมีมาร์กอัป ไม่จำเป็นต้องเป็นองค์ประกอบเดียว มันจะไม่มีเหตุผลอย่างยิ่งที่จะกำหนด@classเทมเพลตตัวแก้ไขที่มี 3 div เช่น ตัวช่วย Html.TextBoxFor ช่วยให้คุณกำหนดสิ่งนี้ได้เนื่องจากคุณรู้ว่าตัวช่วยนี้สร้างอะไร - กล่องข้อความดังนั้นจึงเหมาะสมที่จะกำหนดคลาสให้กับองค์ประกอบอินพุต
Darin Dimitrov

115

การอัปเดต MVC 5.1 รองรับวิธีการด้านล่างโดยตรงแล้วดังนั้นจึงใช้งานได้กับตัวแก้ไขในตัว http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (เป็นกรณีที่ Great mind คิดเหมือนกันหรืออ่านคำตอบของฉัน :)

สิ้นสุดการอัปเดต

หากคุณใช้เทมเพลตตัวแก้ไขของคุณเองหรือด้วย MVC 5.1 ซึ่งตอนนี้สนับสนุนแนวทางด้านล่างโดยตรงสำหรับเครื่องมือแก้ไขในตัว

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

จากนั้นในเทมเพลตของคุณ (ไม่จำเป็นสำหรับประเภทธรรมดาใน MVC 5.1)

@Html.TextBoxFor(m => m, ViewData["htmlAttributes"])

5
คุณลักษณะใหม่นี้ช่วยแก้ปัญหาเดิมที่ถามเมื่อสี่ปีก่อนได้อย่างสมบูรณ์แบบ
CoderSteve

1
หากแทนที่จะเป็น TextBoxFor และผู้ช่วยเช่นนั้นฉันใช้เทมเพลตตัวแก้ไขแบบกำหนดเองจำนวนมากฉันจะไม่บอกว่ามันเป็นความคิดที่ยอดเยี่ยมในการเพิ่ม ViewData [... ] ลงในแต่ละรายการ ... :(
Alexander

42

ใน MVC 5.1 คุณสามารถทำสิ่งต่อไปนี้ได้:

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

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


ลิงค์ข้างบนตายแล้ว สามารถดูได้ใน MVC 5.1 ดูข้อมูลเพิ่มเติมได้ที่นี่: asp.net/mvc/overview/releases/mvc51-release-notes#new-features
Alaa Masoud

1
ขอบคุณฉันแก้ไขลิงก์แล้วเช่นกัน
vtforester

2
วิธีการผสาน htmlAttributes
Bart Calixto

ใช้งานได้กับEditorForเทมเพลตในตัว / เริ่มต้นเท่านั้น หากคุณใช้งานของคุณเองคุณต้องทำตามคำตอบของ AntonK
mxmissile

6

ตอนนี้ASP.Net MVC 5.1ได้รับการสนับสนุนในตัวแล้ว

จากบันทึกประจำรุ่น

ตอนนี้เราอนุญาตให้ส่งผ่านแอตทริบิวต์ HTML ใน EditorFor เป็นวัตถุที่ไม่ระบุตัวตน

ตัวอย่างเช่น:

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

4

นี่คือไวยากรณ์รหัส VB.Netสำหรับแอตทริบิวต์ html ใน MVC 5.1 EditorFor

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

3

ทำไมไม่ใช้

@Html.DisplayFor(model => model.Control.PeriodType)

30
เหตุผลหนึ่งคือ DisplayFor ไม่แสดงผลอินพุตดังนั้นค่าจะหายไปเมื่อโพสต์แบ็ค

2
อีกเหตุผลหนึ่งคือสถานการณ์เฉพาะที่ตัวแก้ไขอยู่ในขณะนี้ แต่ไม่ได้ล็อกตลอดเวลาและคุณต้องการสื่อสารว่าข้อมูลนั้นสามารถแก้ไขได้ - ไม่ใช่ตอนนี้
ร์

2

หากคุณไม่ต้องการใช้ข้อมูลเมตาคุณสามารถใช้[UIHint("PeriodType")]แอตทริบิวต์เพื่อตกแต่งคุณสมบัติหรือหากเป็นประเภทที่ซับซ้อนคุณไม่ต้องตกแต่งอะไรเลย จากนั้น EditorFor จะค้นหาไฟล์ PeriodType.aspx หรือ ascx ในโฟลเดอร์ EditorTemplates และใช้สิ่งนั้นแทน


ขอบคุณฉันอาจจะทำเช่นนั้นได้หาก if / else ในเทมเพลตตัวแก้ไขของฉันจำเป็นสำหรับบางช่องเท่านั้น
Typo Johnson

แม้ว่าคุณจะบอกว่าคุณไม่สามารถเปลี่ยนโมเดลได้ (ไม่ใช่รหัสของคุณ) ดังนั้นการตกแต่งด้วย UIHint โดยตรงจึงไม่ใช่ตัวเลือก
Darrel Lee

2

วันนี้ฉันต่อสู้กับปัญหาเดียวกันนี้สำหรับช่องทำเครื่องหมายที่เชื่อมโยงกับบูลที่เป็นโมฆะและเนื่องจากฉันไม่สามารถเปลี่ยนโมเดลของฉันได้ (ไม่ใช่รหัสของฉัน) ฉันจึงต้องหาวิธีที่ดีกว่าในการจัดการสิ่งนี้ มันค่อนข้างดุร้าย แต่มันควรจะใช้ได้กับ 99% ของเคสที่ฉันอาจเจอ เห็นได้ชัดว่าคุณต้องสร้างแอตทริบิวต์ที่ถูกต้องด้วยตนเองสำหรับการป้อนข้อมูลแต่ละประเภท แต่ฉันคิดว่าฉันได้รับทั้งหมดสำหรับช่องทำเครื่องหมาย

ในเทมเพลตตัวแก้ไข Boolean.cshtml ของฉัน:

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

ฉันได้เพิ่มDictionary<string,string> attribs = new Dictionary<string,string>();และattribs.Add("tabindex","16");ในหนึ่งใน@( )บล็อกเหล่านั้นที่ด้านบนของหน้าของฉัน จากนั้นฉันก็ทำ@Html.CheckBox("IsActive", Model.IsActive.HasValue ? Model.IsActive : false, attribs)ในหน้าของฉันและมันทำให้ฉันมีข้อผิดพลาด: "'System.Web.Mvc.HtmlHelper <MyProject.Models.MyObject>' ไม่มีคำจำกัดความสำหรับ 'CheckBox' และวิธีการขยายที่ดีที่สุด overload 'System.Web Mvc.InputExtensions.CheckBox (System.Web.Mvc.HtmlHelper, string.bool, object) 'มีอาร์กิวเมนต์ที่ไม่ถูกต้อง "
vapcguy

2

คุณยังสามารถใช้ EditorFor เพียงแค่ส่ง style / แอตทริบิวต์ html ใดก็ตามที่เป็น ViewData

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

เนื่องจาก EditorFor ใช้เทมเพลตในการแสดงผลคุณจึงสามารถแทนที่เทมเพลตเริ่มต้นสำหรับคุณสมบัติของคุณและส่งผ่านแอตทริบิวต์ style เป็น ViewData

EditorTemplate ของคุณต้องการสิ่งต่อไปนี้:

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

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

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

คุณสามารถใช้เช่นนี้ เอาต์พุตเดียวกันHtml.EditorForและคุณสามารถเพิ่มแอตทริบิวต์ html ของคุณได้


ยกเว้นTextBoxForไม่สนใจประเภทใด ๆDisplayFormatที่คุณอาจพยายามสมัคร
Eric K

1

เพียงสร้างเทมเพลตของคุณเองสำหรับประเภทใน 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"})

เรียกใช้ตัวแก้ไขจากมุมมองของคุณด้วยคุณสมบัติของโมเดล:

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

ให้อภัยไวยากรณ์ VB นั่นเป็นเพียงวิธีที่เราหมุน


1

ในกรณีของฉันฉันพยายามสร้างเทมเพลตตัวแก้ไขการป้อนหมายเลข HTML5 ที่สามารถรับแอตทริบิวต์เพิ่มเติมได้ วิธีการที่ดีกว่าคือการเขียน HTML Helper ของคุณเอง แต่เนื่องจากฉันมีเทมเพลต. ascx อยู่แล้วฉันจึงใช้วิธีนี้:

<%@ 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])%>
       <% }
   } %> />

บิตที่น่าเกลียดนี้จะสร้างอินพุตประเภทตัวเลขและมองหาพจนานุกรม ViewData ที่มีคีย์ "attributes" มันจะวนซ้ำผ่านพจนานุกรมโดยเพิ่มคู่คีย์ / ค่าเป็นแอตทริบิวต์ Regex ในแอตทริบิวต์ ID ไม่เกี่ยวข้องและอยู่ในนั้นเนื่องจากเมื่อใช้ในคอลเล็กชันGetFullHtmlFieldId()จะส่งคืน id ที่มีวงเล็บเหลี่ยม[]ซึ่งโดยปกติจะใช้ Escape เป็นเครื่องหมายขีดล่าง

เทมเพลตนี้เรียกแบบนี้:

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

Verbose แต่ได้ผล คุณอาจใช้การสะท้อนในเทมเพลตเพื่อใช้ชื่อคุณสมบัติเป็นชื่อแอตทริบิวต์แทนการใช้พจนานุกรม


1

กำหนดเงื่อนไขโดยใช้ViewDataในคอนโทรลเลอร์

ViewData["Modifiable"] = model.recProcessed;

จากนั้นใช้ viewdata นี้ในเทมเพลตตัวแก้ไขเพื่อตั้งค่าแอตทริบิวต์ html ของตัวควบคุม

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

0

MVC 5.1 และโซลูชันที่สูงกว่า (จะรวม HtmlAttributes ในเครื่องและกำหนดไว้ใน EditorTemplates):

Shared \ EditorTemplates \ String.cshtml:

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

ส่วนขยาย:

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

การใช้งาน:

@Html.EditorFor(m => m.PromotionalCode, new { htmlAttributes = new { ng_model = "roomCtrl.searchRoomModel().promoCode" }})

1
ขอบคุณที่ได้ผล ยกเว้นสำหรับทุกคุณลักษณะ data_xxx ที่ฉันมีการแทนที่ด้วย _ - เมื่อหล่อsource1และเป็นsource2 IDictionary<string, object>ฉันทำหน้าที่นี้: private static IDictionary<string, object> ToHtmlAttributesDictionary(this IEnumerable<KeyValuePair<string, object>> dico) { return dico.ToDictionary(s => s.Key.Replace('_', '-'), s => s.Value); }
Marien Monnier
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.