HTML-Attribute für EditorFor () in ASP.NET MVC


129

Warum kann ich keine HTML-Attribute an übergeben EditorFor()? z.B;

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

Ich möchte keine Metadaten verwenden

Update : Die Lösung bestand darin, dies aus der Sicht aufzurufen:

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

und ViewData["Modifiable"]in meiner benutzerdefinierten EditorTemplates / String.ascx verwenden, wo ich eine Ansichtslogik habe, die bestimmt, ob schreibgeschützte und / oder deaktivierte Attribute zur Eingabe hinzugefügt werden sollen. Das übergebene anonyme Objekt EditorFor()ist ein Parameter, der aufgerufen wird, additionalViewDataund seine Eigenschaften werden an die Editorvorlage in der übergeben ViewDataSammlung.


19
Im Ernst, immer noch in MVC3 hat diese Einschränkung keinen Sinn und ist wirklich ärgerlich. Menschen auf der ganzen Welt verbringen Zeit und ziehen sich mit diesem Unsinn die Haare aus. Ich sende dies an Microsoft Connect.
Junior Mayhé


3
Ist es nur ich oder scheint das eine Menge BS für etwas zu sein, das soooo einfach sein sollte?
Eric K

Vielleicht hilft Ihnen dies: [EditorFor-Implementierung mit CSS-Klassen und HTML-Attributen] [1] [1]: stackoverflow.com/questions/12675708/…
FunThom

Antworten:


96

EditorForfunktioniert mit Metadaten. Wenn Sie also HTML-Attribute hinzufügen möchten, können Sie dies jederzeit tun . Eine andere Möglichkeit besteht darin, einfach eine benutzerdefinierte Vorlage zu schreiben und Folgendes zu verwenden TextBoxFor:

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

Die Metadaten funktionieren nicht, da die HTML-Attribute abhängig von anderen Eigenschaften im Modell variieren. Mit anderen Worten, die Domänen- oder Viemodell-Logik sollte die HTML-Attribute bestimmen, nicht die statischen Metadaten. Oder fehlt mir der Punkt, kann ich Metadaten dynamisch einstellen?
Tippfehler Johnson

Was ist PeriodType? Ist es nicht eine einfache Eigenschaft? Wenn es sich um ein komplexes Objekt ist , könnte man konnte die ganze Vorlage anpassen , indem Sie eine Teil platzieren , ~/Views/ControllerName/EditorTemplates/SomeType.ascxwo SomeTypeder Name des Typs ist PeriodTypeEigentum.
Darin Dimitrov

Ihr vorgeschlagener Code würde auch bedeuten, das gesamte Modell an eine Teilvorlage zu übergeben, die auf eine bestimmte Eigenschaft zugreift. Dies würde bedeuten, dass ich für jede Eigenschaft eine Teilvorlage habe.
Tippfehler Johnson

2
Ich verstehe dich jetzt. Ich kann <% = Html.EditorFor (model => model.Control.PeriodEndDate, new {Modutable = model.Control.PeriodEndDateModizable})%> verwenden und ViewData ["PeriodEndDateModutable"] in meinen benutzerdefinierten EditorTemplates / String.ascx verwenden. Vielen Dank
Tippfehler Johnson

1
@ JuniorMayhé, ich würde das nicht als langweilige Einschränkung bezeichnen. Wenn Sie genauer überlegen, werden Sie verstehen, dass dies sinnvoll ist. Der springende Punkt des EditorFor-Hilfsprogramms ist, dass Sie eine entsprechende Vorlage haben könnten. Diese Vorlage kann ein beliebiges Markup enthalten. Nicht unbedingt ein einzelnes Element. Es wäre absolut @classsinnlos, eine Editorvorlage zu definieren , die beispielsweise 3 Divs enthält. Mit dem Html.TextBoxFor-Helfer können Sie dies definieren, da Sie wissen, was dieser Helfer generiert - ein Textfeld, daher ist es sinnvoll, eine Klasse für ein Eingabeelement zu definieren.
Darin Dimitrov

115

Das Update MVC 5.1 unterstützt jetzt den folgenden Ansatz direkt, sodass es auch für den integrierten Editor funktioniert. http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (Es ist entweder ein Fall von großartigem Denken oder sie lesen meine Antwort :)

Update beenden

Wenn Sie Ihre eigene Editor-Vorlage oder MVC 5.1 verwenden, das jetzt den folgenden Ansatz direkt für integrierte Editoren unterstützt.

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

dann in Ihrer Vorlage (nicht erforderlich für einfache Typen in MVC 5.1)

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

5
Diese neue Funktion löst das ursprüngliche Problem, das vor vier Jahren gestellt wurde, perfekt.
CoderSteve

1
Wenn ich anstelle von TextBoxFor und solchen Helfern Tonnen von benutzerdefinierten Editorvorlagen verwende, würde ich nicht sagen, dass es eine fantastische Idee ist, ViewData [...] in jede von ihnen einzufügen ... :(
Alexander

42

Ab MVC 5.1 können Sie jetzt Folgendes tun:

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

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


Der obige Link ist tot. Dies ist in MVC 5.1 verfügbar, weitere Informationen hier: asp.net/mvc/overview/releases/mvc51-release-notes#new-features
Alaa Masoud

1
Danke, ich habe auch den Link repariert.
Vtforester

2
Wie füge ich htmlAttributes zusammen?
Bart Calixto

Dies funktioniert nur mit den eingebauten / EditorForStandardvorlagen. Wenn Sie Ihre eigenen implementieren, müssen Sie der Antwort von AntonK folgen.
mxmissile

6

Jetzt hat ASP.Net MVC 5.1 eine integrierte Unterstützung dafür erhalten.

Aus den Versionshinweisen

Wir erlauben jetzt die Übergabe von HTML-Attributen in EditorFor als anonymes Objekt.

Beispielsweise:

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

4

Hier ist die VB.Net-Codesyntax für HTML-Attribute in MVC 5.1 EditorFor

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

3

Warum nicht einfach benutzen

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

30
Ein Grund dafür ist, dass DisplayFor keine Eingabe rendert, sodass der Wert beim Postback verloren geht.
ProfK

2
Ein weiterer Grund ist das spezielle Szenario, in dem der Editor derzeit, aber nicht immer gesperrt ist und Sie mitteilen möchten, dass die Daten möglicherweise bearbeitet werden können - nur nicht jetzt.
Mir

2

Wenn Sie keine Metadaten verwenden möchten, können Sie [UIHint("PeriodType")]die Eigenschaft mit einem Attribut dekorieren, oder wenn es sich um einen komplexen Typ handelt, müssen Sie nichts dekorieren. EditorFor sucht dann im EditorTemplates-Ordner nach einer PeriodType.aspx- oder ASCX-Datei und verwendet diese stattdessen.


Vielen Dank, ich kann das am Ende tun, wenn das if / else in meiner Editor-Vorlage nur für bestimmte Felder erforderlich ist
Typo Johnson

Ich dachte, Sie sagten, Sie könnten das Modell (nicht Ihren Code) nicht ändern, daher wäre eine direkte Dekoration mit UIHint keine Option.
Darrel Lee

2

Ich habe heute mit dem gleichen Problem um ein Kontrollkästchen gerungen, das an einen nullbaren Bool gebunden ist, und da ich mein Modell (nicht meinen Code) nicht ändern kann, musste ich mir eine bessere Methode ausdenken, um damit umzugehen. Es ist ein bisschen rohe Gewalt, aber es sollte in 99% der Fälle funktionieren, denen ich begegnen könnte. Sie müssten natürlich eine manuelle Auffüllung gültiger Attribute für jeden Eingabetyp durchführen, aber ich glaube, ich habe alle für das Kontrollkästchen erhalten.

In meiner Boolean.cshtml-Editorvorlage:

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

Ich habe Dictionary<string,string> attribs = new Dictionary<string,string>();und attribs.Add("tabindex","16");in einem dieser @( )Blöcke oben auf meiner Seite hinzugefügt . Dann habe ich @Html.CheckBox("IsActive", Model.IsActive.HasValue ? Model.IsActive : false, attribs)auf meiner Seite und es gibt mir eine Fehlermeldung: "'System.Web.Mvc.HtmlHelper <MyProject.Models.MyObject>' enthält keine Definition für 'CheckBox' und die beste Erweiterungsmethode Überladung 'System.Web. Mvc.InputExtensions.CheckBox (System.Web.Mvc.HtmlHelper, string.bool, object) 'hat einige ungültige Argumente ".
Vapcguy

2

Sie können EditorFor weiterhin verwenden. Übergeben Sie einfach das HTML-Attribut style / whichever als ViewData.

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

Da EditorFor zum Rendern Vorlagen verwendet, können Sie die Standardvorlage für Ihre Eigenschaft überschreiben und das Stilattribut einfach als ViewData übergeben.

Ihre EditorTemplate möchte also Folgendes:

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

Sie können so verwenden; gleiche Ausgabe mit Html.EditorFor, und Sie können Ihre HTML-Attribute hinzufügen


Außer TextBoxForignoriert jede Art von dem DisplayFormat, was Sie möglicherweise anwenden möchten.
Eric K

1

Erstellen Sie einfach Ihre eigene Vorlage für den Typ in 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"})

Rufen Sie den Editor aus Ihrer Ansicht mit der Modelleigenschaft auf:

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

Verzeihen Sie die VB-Syntax. So rollen wir.


1

In meinem Fall habe ich versucht, eine HTML5-Eingabe-Editor-Vorlage zu erstellen, die zusätzliche Attribute erhalten kann. Ein besserer Ansatz wäre es, einen eigenen HTML-Helfer zu schreiben. Da ich jedoch bereits meine .ascx-Vorlage hatte, habe ich mich für diesen Ansatz entschieden:

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

Dieses hässliche Bit erstellt eine Eingabe vom Typ Zahl und sucht nach einem ViewData-Wörterbuch mit dem Schlüssel "Attribute". Es wird das Wörterbuch durchlaufen und seine Schlüssel / Wert-Paare als Attribute hinzufügen. Der Regex im ID-Attribut hat keine Beziehung und ist vorhanden, da bei Verwendung in einer Sammlung GetFullHtmlFieldId()eine ID mit eckigen Klammern zurückgegeben wird, []die normalerweise als Unterstriche maskiert wird.

Diese Vorlage heißt dann wie folgt:

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

Ausführlich, aber es funktioniert. Sie könnten wahrscheinlich die Reflektion in der Vorlage verwenden, um Eigenschaftsnamen als Attributnamen zu verwenden, anstatt ein Wörterbuch zu verwenden.


1

Stellen Sie die Bedingung mit ViewDatain der Steuerung ein

ViewData["Modifiable"] = model.recProcessed;

Verwenden Sie dann diese Ansichtsdaten in der Editorvorlage, um das HTML-Attribut des Steuerelements festzulegen

@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 und eine höhere Lösung (führt lokale HtmlAttributes zusammen und wird in den EditorTemplates definiert):

Shared \ EditorTemplates \ String.cshtml:

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

Erweiterungen:

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

Verwendung:

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

1
Danke, das funktioniert. Mit Ausnahme aller data_xxx-Attribute, bei denen ich beim Casting source1und source2as _ durch - ersetzen musste IDictionary<string, object>. Ich habe diese Funktion gemacht: private static IDictionary<string, object> ToHtmlAttributesDictionary(this IEnumerable<KeyValuePair<string, object>> dico) { return dico.ToDictionary(s => s.Key.Replace('_', '-'), s => s.Value); }
Marien Monnier
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.