Thuộc tính Html cho EditorFor () trong ASP.NET MVC


129

Tại sao tôi không thể chuyển các thuộc tính html sang EditorFor()? ví dụ;

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

Tôi không muốn sử dụng siêu dữ liệu

Cập nhật : Giải pháp là gọi nó từ chế độ xem:

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

và sử dụng ViewData["Modifiable"]trong EditorTem mẫu / String.ascx tùy chỉnh của tôi trong đó tôi có một số logic xem để xác định xem có nên thêm thuộc tính chỉ đọc và / hoặc bị vô hiệu hóa vào đầu vào Đối tượng ẩn danh được truyền vào EditorFor()là một tham số được gọi additionalViewDatavà các thuộc tính của nó được chuyển đến mẫu trình soạn thảo trong ViewDatabộ sưu tập.


19
Nghiêm túc mà nói, vẫn còn trong MVC3 giới hạn này không có ý nghĩa và nó thực sự gây phiền nhiễu. Mọi người trên khắp thế giới đang dành thời gian và nhổ tóc với điều vô nghĩa này. Tôi đang gửi cái này đến Microsoft Connect.
Junior Mayhé


3
Có phải chỉ có tôi, hoặc có vẻ như rất nhiều bs cho một cái gì đó rất đơn giản?
Eric K

Có lẽ điều này sẽ giúp bạn: [Trình chỉnh sửa thực hiện với các lớp CSS và thuộc tính HTML] [1] [1]: stackoverflow.com/questions/12675708/
trộm

Bản sao có thể có của các thuộc tính EditorFor () và html
Gyrfalcon

Câu trả lời:


96

EditorForhoạt động với siêu dữ liệu, vì vậy nếu bạn muốn thêm các thuộc tính html, bạn luôn có thể làm điều đó . Một tùy chọn khác là chỉ cần viết một mẫu tùy chỉnh và sử dụng TextBoxFor:

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

Siêu dữ liệu sẽ không hoạt động vì các thuộc tính html khác nhau tùy thuộc vào các thuộc tính khác trong mô hình, nói cách khác, tên miền hoặc logic viemodel sẽ xác định các thuộc tính html không phải siêu dữ liệu tĩnh. Hoặc tôi đang thiếu điểm, tôi có thể thiết lập siêu dữ liệu động không?
Typo Johnson

PeriodTypegì Nó không phải là một tài sản đơn giản? Nếu đó là một đối tượng phức tạp, bạn có thể tùy chỉnh toàn bộ mẫu bằng cách đặt một phần trong ~/Views/ControllerName/EditorTemplates/SomeType.ascxđó SomeTypelà tên loại của thuộc PeriodTypetính.
Darin Dimitrov

Ngoài ra mã được đề xuất của bạn có nghĩa là chuyển toàn bộ mô hình vào một phần mẫu để truy cập vào một thuộc tính cụ thể, điều này có nghĩa là tôi có một phần cho mỗi thuộc tính?
Typo Johnson

2
Tôi có được bạn bây giờ. Tôi có thể sử dụng <% = Html.EditorFor (model => model.Control.PeriodEndDate, new {Modifiable = model.Control.PeriodEndDateModifiable})%> và sử dụng ViewData ["periodEndDateModifiable" Cảm ơn
Typo Johnson

1
@ JuniorMayhé, tôi sẽ không gọi đây là một giới hạn nhàm chán. Nếu bạn suy nghĩ kỹ hơn bạn sẽ hiểu rằng điều này có ý nghĩa. Trong thực tế, toàn bộ quan điểm của trình trợ giúp EditorFor là bạn có thể có một mẫu tương ứng. Mẫu này có thể chứa bất kỳ đánh dấu. Không nhất thiết là một yếu tố duy nhất. Nó sẽ hoàn toàn không có ý nghĩa để xác định @classcho một mẫu biên tập có chứa 3 div chẳng hạn. Trình trợ giúp Html.TextBoxFor cho phép bạn xác định điều này bởi vì bạn biết trình trợ giúp này tạo ra cái gì - một hộp văn bản để xác định một lớp thành một phần tử đầu vào có ý nghĩa.
Darin Dimitrov

115

Cập nhật MVC 5.1 hiện hỗ trợ trực tiếp cách tiếp cận bên dưới, vì vậy nó cũng hoạt động với trình soạn thảo tích hợp. http://www.asp.net/mvc/overview/release/mvc51-release-notes#new-features (Đó là một trường hợp của Great mind suy nghĩ giống nhau hoặc họ đọc câu trả lời của tôi :)

Kết thúc cập nhật

Nếu bạn sử dụng mẫu trình soạn thảo của riêng bạn hoặc với MVC 5.1 hiện hỗ trợ cách tiếp cận dưới đây trực tiếp cho các trình soạn thảo tích hợp.

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

sau đó trong mẫu của bạn (không bắt buộc đối với các loại đơn giản trong MVC 5.1)

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

5
Tính năng mới này giải quyết hoàn hảo vấn đề ban đầu được hỏi bốn năm trước.
CoderSteve

1
Nếu thay vì TextBoxFor và những người trợ giúp như tôi sử dụng hàng tấn mẫu trình soạn thảo tùy chỉnh, tôi sẽ không nói rằng đó là một ý tưởng tuyệt vời để thêm ViewData [...] vào mỗi trong số chúng ... :(
Alexander

42

Kể từ MVC 5.1, bây giờ bạn có thể làm như sau:

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

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


Các liên kết trên là chết. Điều này có sẵn trong MVC 5.1, thông tin thêm ở đây: asp.net/mvc/overview/release/mvc51-release-notes#new-features
Alaa Masoud

1
Cảm ơn, tôi đã sửa liên kết là tốt.
vtforester

2
Làm cách nào để hợp nhất htmlAttribution?
Bart Calixto

Điều này chỉ hoạt động với các mẫu được xây dựng trong / mặc định EditorFor. Nếu bạn tự thực hiện, bạn phải tuân theo câu trả lời của AntonK.
mxmissile

6

Bây giờ, ASP.Net MVC 5.1 đã tích hợp sẵn hỗ trợ cho nó.

Từ ghi chú phát hành

Bây giờ chúng tôi cho phép chuyển các thuộc tính HTML trong EditorFor dưới dạng đối tượng ẩn danh.

Ví dụ:

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

4

Đây là cú pháp mã VB.Net cho các thuộc tính html trong MVC 5.1 EditorFor

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

3

Tại sao không sử dụng

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

30
Một lý do là DisplayFor không hiển thị đầu vào, vì vậy giá trị bị mất khi gửi lại.
ProfK

2
Một lý do khác là kịch bản cụ thể trong đó trình soạn thảo hiện đang bị khóa nhưng không phải lúc nào cũng bị khóa và bạn muốn thông báo rằng dữ liệu có khả năng chỉnh sửa - không phải bây giờ.
Mir

2

Nếu bạn không muốn sử dụng Siêu dữ liệu, bạn có thể sử dụng một [UIHint("PeriodType")]thuộc tính để trang trí thuộc tính hoặc nếu đó là một loại phức tạp, bạn không phải trang trí bất cứ thứ gì. Sau đó, EditorFor sẽ tìm một tệp periodType.aspx hoặc ascx trong thư mục EditorTem mẫu và sử dụng nó để thay thế.


Cảm ơn, tôi có thể sẽ làm điều đó nếu if / other trong mẫu trình soạn thảo của tôi chỉ được yêu cầu cho một số trường nhất định
Typo Johnson

Tôi mặc dù bạn nói rằng bạn không thể thay đổi mô hình (không phải mã của bạn), vì vậy trang trí trực tiếp với UIHint sẽ không phải là một lựa chọn.
Darrel Lee

2

Tôi đã vật lộn với cùng một vấn đề ngày hôm nay vì một hộp kiểm liên kết với một bool nullable và vì tôi không thể thay đổi mô hình của mình (không phải mã của tôi), tôi đã phải đưa ra cách xử lý tốt hơn. Đó là một chút vũ phu, nhưng nó sẽ hoạt động cho 99% trường hợp tôi có thể gặp phải. Rõ ràng là bạn phải thực hiện một số quần thể thuộc tính thủ công cho từng loại đầu vào, nhưng tôi nghĩ rằng tôi đã nhận được tất cả chúng cho hộp kiểm.

Trong mẫu trình soạn thảo Boolean.cshtml của tôi:

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

Tôi đã thêm Dictionary<string,string> attribs = new Dictionary<string,string>();attribs.Add("tabindex","16");vào một trong những @( )khối đó ở đầu trang của tôi. Sau đó, tôi đã làm @Html.CheckBox("IsActive", Model.IsActive.HasValue ? Model.IsActive : false, attribs)trên trang của mình và nó báo lỗi: "'System.Web.Mvc.HtmlHelper <MyProject.Models.MyObject>' không chứa định nghĩa cho 'CheckBox' và quá tải phương thức mở rộng tốt nhất 'System.Web. Mvc.InputExtensions.CheckBox (System.Web.Mvc.HtmlHelper, string.bool, object) 'có một số đối số không hợp lệ ".
vapcguy

2

Bạn vẫn có thể sử dụng EditorFor. Chỉ cần chuyển thuộc tính kiểu / tùy chọn html nào dưới dạng ViewData.

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

Vì EditorFor sử dụng các mẫu để kết xuất, bạn có thể ghi đè mẫu mặc định cho thuộc tính của mình và chỉ cần chuyển thuộc tính kiểu là ViewData.

Vì vậy, EditorTemplate của bạn muốn như sau:

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

bạn có thể sử dụng như thế này; cùng một đầu ra với Html.EditorForvà bạn có thể thêm các thuộc tính html của mình


Ngoại trừ TextBoxForbỏ qua bất kỳ loại nào DisplayFormatmà bạn có thể đang cố gắng áp dụng.
Eric K

1

Chỉ cần tạo mẫu của riêng bạn cho loại trong Lượt xem / Được chia sẻ / Trình soạn thảo / Bản mẫu / 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"})

Gọi trình soạn thảo từ chế độ xem của bạn với thuộc tính mô hình:

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

Xin lỗi cú pháp VB. Đó chỉ là cách chúng tôi lăn.


1

Trong trường hợp của tôi, tôi đã cố gắng tạo một mẫu trình soạn thảo đầu vào số HTML5 có thể nhận các thuộc tính bổ sung. Cách tiếp cận gọn gàng hơn là viết Trình trợ giúp HTML của riêng bạn, nhưng vì tôi đã có mẫu .ascx của mình, tôi đã thực hiện theo cách tiếp cận này:

<%@ 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 xấu xí này tạo ra một kiểu nhập số và tìm từ điển ViewData với các "thuộc tính" chính. Nó sẽ lặp qua từ điển thêm các cặp khóa / giá trị của nó làm thuộc tính. Regex trong thuộc tính ID không liên quan và có bởi vì khi được sử dụng trong bộ sưu tập, GetFullHtmlFieldId()sẽ trả về một id chứa dấu ngoặc vuông []mà nó thường thoát dưới dạng dấu gạch dưới.

Mẫu này sau đó được gọi như thế này:

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

Verbose, nhưng nó hoạt động. Bạn có thể có thể sử dụng sự phản chiếu trong mẫu để sử dụng tên thuộc tính làm tên thuộc tính thay vì sử dụng từ điển.


1

Đặt điều kiện sử dụng ViewDatatrong bộ điều khiển

ViewData["Modifiable"] = model.recProcessed;

Sau đó sử dụng viewdata này trong mẫu trình soạn thảo để đặt thuộc tính html của điều khiển

@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 và giải pháp cao hơn (sẽ hợp nhất HtmlAttribution cục bộ và được xác định trong EditorTemsheet):

Được chia sẻ \ EditorTem mẫu \ String.cshtml:

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

Tiện ích mở rộng:

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

Sử dụng:

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

1
Cảm ơn, điều đó làm việc. Ngoại trừ tất cả các thuộc tính data_xxx, nơi tôi phải thay thế _ bằng - khi truyền source1source2dưới dạng IDictionary<string, object>. Tôi đã thực hiện chức năng này: private static IDictionary<string, object> ToHtmlAttributesDictionary(this IEnumerable<KeyValuePair<string, object>> dico) { return dico.ToDictionary(s => s.Key.Replace('_', '-'), s => s.Value); }
Marien Monnier
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.