Атрибути 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.
Молодший Мейхе


3
Це тільки я, або це здається великою кількістю біс для чогось, що повинно бути так просто?
Ерік К

Може бути , це допоможе вам: [EditorFor-реалізація з класами CSS і HTML атрибути] [1] [1]: stackoverflow.com/questions/12675708 / ...
FunThom

Можливий дублікат властивостей EditorFor () та html
Gyrfalcon

Відповіді:


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властивості.
Дарин Димитров

Також запропонований вами код означатиме передачу всієї моделі в частковий шаблон, який має доступ до певного властивості, це означатиме, що я маю частковий для кожного властивості?
Typo Johnson

2
Я тебе зараз отримую. Я можу використовувати <% = Html.EditorFor (model => model.Control.PeriodEndDate, новий {Modifiable = model.Control.PeriodEndDateModifiable})>> та використовувати ViewData ["PeriodEndDateModifiable"] у своєму користувальницькому редакторіTemplax / String.as. Спасибі
Typo Johnson

1
@ JuniorMayhé, я б не назвав це нудним обмеженням. Якщо ви подумаєте більш ретельно, то зрозумієте, що це має сенс. Насправді вся суть помічника EditorFor полягає в тому, що у вас може бути відповідний шаблон. Цей шаблон може містити будь-яку розмітку. Не обов’язково один елемент. Не було б сенсу визначати @classшаблон редактора, який містить, наприклад, 3 діви. Помічник Html.TextBoxFor дозволяє визначити це, оскільки ви знаєте, що генерує цей помічник - текстове поле, тому має сенс визначати клас для елемента введення.
Дарин Димитров

115

Оновлення MVC 5.1 тепер підтримує наступний підхід безпосередньо, тому він працює і для вбудованого редактора. http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (Це або випадок, коли великий розум думає так, або вони читають мою відповідь :)

Закінчити оновлення

Якщо ви використовуєте власний шаблон редактора або з 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 [...] до кожного з них ... :(
Олександр

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
Алаа Масуд

1
Дякую, я також виправив посилання.
vtforester

2
як об'єднати htmlAttributes?
Барт Калікто

Це працює лише із вбудованими / за замовчуванням EditorForшаблонами. Якщо ви реалізуєте своє, вам доведеться слідувати відповіді AntonK.
mxmissle


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 і використовуватиме його замість цього.


Дякую, я можу зробити це, якщо в моєму редакторі шаблон потрібен лише для певних полів
Typo Johnson,

Я хоч і сказав, що ви не можете змінити модель (не свій код), тому декорування за допомогою UIHint безпосередньо не буде варіантом.
Даррел Лі

2

Я сьогодні боровся з тим же питанням за прапорець, який пов'язує нульовий bool, і оскільки я не можу змінити свою модель (не свій код), мені довелося придумати кращий спосіб вирішення цього питання. Це трохи груба сила, але це повинно працювати в 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 "і найкращий метод розширення перевантажує" System.Web. Mvc.InputExtensions.CheckBox (System.Web.Mvc.HtmlHelper, string.bool, object) "має деякі недійсні аргументи".
vapcguy

2

Ви все ще можете скористатися EditorFor. Просто передайте атрибут стилю / залежно від html як ViewData.

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

Оскільки EditorFor використовує шаблони для візуалізації, ви можете замінити шаблон за замовчуванням для вашого ресурсу та просто передати атрибут стилю як ViewData.

Тож ваш редакторTemplate хотів би наступного:

@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який ви можете намагатися застосувати.
Ерік К

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 з ключовими "атрибутами". Він повторить словник, додаючи його атрибути пар ключів / значень. Regex в атрибуті ID не пов'язаний між собою і є, оскільки при використанні у колекції GetFullHtmlFieldId()повертає ідентифікатор, що містить квадратні дужки[] які, як правило, уникають як підкреслення.

Потім цей шаблон називається так:

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

Багатослівний, але це працює. Можливо, ви можете використовувати відображення в шаблоні, щоб використовувати імена властивостей як імена атрибутів, а не використовувати словник.


1

Встановіть умову, використовуючи ViewDataв контролері

ViewData["Modifiable"] = model.recProcessed;

Потім використовуйте ці представлені дані в шаблоні редактора, щоб встановити атрибут 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 та визначено у редакторахTemplates):

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); }
Марієн Моньє
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.