ASP.NET MVC-Rasierer: Bedingtes Attribut in HTML

83

Der folgende Code scheint nicht sauber zu sein. Irgendwelche Vorschläge zur Verbesserung des Codes?

<li @if(ViewData["pagename"].ToString()=="Business details"){ <text>class="active" </text> } >
        <a  @if(ViewData["pagename"].ToString()=="Business details"){ <text>style="color: white; background-color: #08C; border: 1px solid #08C;" </text> }
            href="@Url.Action("BusinessDetails", "Business")">Business Details</a>
    </li> 
    <li @if (ViewData["pagename"].ToString() == "Booking policies"){ <text>class="active"</text> }> 
        <a  @if (ViewData["pagename"].ToString() == "Booking policies")
               { <text>style="color: white; background-color: #08C; border: 1px solid #08C;" </text> }
            href="@Url.Action("BookingPolicies", "Business")">Booking policies</a> 
    </li> 
Mahesh
quelle
Vielleicht einen benutzerdefinierten HTML-Helfer erstellen, der die LI mit untergeordneten Linkelementen rendert?
Nick Bork

Antworten:

138

MVC verfügt über integrierte ...

<div @{if (myClass != null) { <text>class="@myClass"</text> } }>Content</div>
<div class="@myClass">Content</div>

Wenn @myClass null ist, wird das Attribut überhaupt nicht verwendet ...

Ich weiß, dass dies Ihr aktuelles Problem möglicherweise nicht ganz löst, aber es ist bemerkenswert!

http://weblogs.asp.net/jgalloway/archive/2012/02/16/asp-net-4-beta-released.aspx

jcreamer898
quelle
Achten Sie darauf, dass Ihr Klassenname nicht "aktiv" ist, da Sie sonst ein Eintragsklassenattribut haben. Keine Ahnung warum.
ScottE
2
Gibt es eine Möglichkeit, beim Aufruf von HTML-Helfern, die das anonyme htmlPropertiesObjekt übergeben , dasselbe Null-Respekt-Verhalten zu erzielen ? Zum Beispiel möchte ich Attribut bedingt weitergeben disabled, wie @Html.TextBoxFor(lambda, new { disabled = condition ? true : null }), aber das macht immer noch , disabled=""wenn disabledwar null, die die gleiche wie rendring ist , disabled="anything"da disabledist aktiv , wenn das Attribut vorhanden ist, unabhängig vom Wert. Gefunden stackoverflow.com/q/7978137/11683 zum Thema, aber es gibt bessere Möglichkeiten , heute frage ich mich?
GSerg
1
Randnotiz: "data -..." Attribute können nicht bedingt sein und leeren Wert auch für null rendern ( stackoverflow.com/questions/13267619/… )
Alexei Levenkov
74
<li class="@(ViewBag.pagename == "Business details" ? "active" : null)">  

Sie sollten die Inline style="..."durch einen separaten Klassennamen ersetzen und dort dieselbe Syntax verwenden.

Es wäre jedoch sauberer, eine separate HTML-Hilfserweiterungsmethode zu erstellen, die einen Seiten- und Aktionsnamen verwendet und den HTML-Code generisch generiert.

SLaks
quelle
Schön, viel sauberer als einige der anderen Optionen (außer der Razor 2.0-Option).
Ctrlplusb
21

Ich verwende eine kleine Hilfsmethode, die bedingt ein Attribut hinzufügt, wenn der Wert nicht leer ist, und, falls definiert, wenn ein boolescher Funktionsausdruck Folgendes ergibt true:

public static MvcHtmlString Attr(this HtmlHelper helper, string name, string value, Func<bool> condition = null)
{
    if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
    {
        return MvcHtmlString.Empty;
    }

    var render = condition != null ? condition() : true;

    return render ? 
        new MvcHtmlString(string.Format("{0}=\"{1}\"", name, HttpUtility.HtmlAttributeEncode(value))) : 
        MvcHtmlString.Empty;
}

Einmal definiert, kann ich diese Methode in meinen Razor-Ansichten verwenden:

<li @(Html.Attr("class", "new", () => example.isNew))>
...
</li>

Der obige Code wird übertragen , <li class="new">...</li>wenn example.isNew == true, wenn nicht das gesamte weglassen wird classAttribut.

auftauen
quelle
1
Sehr elegante Art, das zu tun. Aber anstelle von Func<bool>Lambda werde ich einen einfachen bool?Parameter bevorzugen , weil es einfacher ist:<li @Html.Attr("class", "new", example.isNew)>
T-Moty
Ich mag diesen Ansatz, weil ein Großteil des benutzerdefinierten JavaScript in meiner App noch ausgeführt wird, wenn der Attributname noch vorhanden ist. Und zumindest führt dies dazu, dass Sie aufgrund von Attributunterschieden nicht dasselbe Div wiederholen. Vielen Dank!
Ben Sewards
4

In MVC4

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        string css = "myDiv";
    }
    <div class='@css'></div>
</body>
</html>

oder

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        string css = "class=myDiv";
    }
    <div @css></div>
</body>
</html>

Weitere finden Sie hier: http://evolpin.wordpress.com/2012/05/20/mvc-4-code-enhancements/

David Slavík
quelle
0

Vorgehensweise mit der TagWrap-Erweiterungsmethode. Der Code für Ihre Frage würde folgendermaßen aussehen:

@using (Html.TagWrap("li", condition ? new { @class = "active" } : null))
{
    var anchorAttrs = new Dictionary<string, object> { { "href", Url.Action("BusinessDetails", "Business") } };
    if(condition)
    {
        anchorAttrs["style"] = "color: white; background-color: #08C; border: 1px solid #08C;";
    }
    using (Html.TagWrap("a", anchorAttrs))
    {
        <text>Business Details</text>
    }
}

TagWrap-Erweiterungsmethoden

Verwenden von Microsoft.AspNetCore.Mvc.ViewFeatures;

public static IDisposable TagWrap(this IHtmlHelper htmlHelper, string tagName, object data)
{
    return htmlHelper.TagWrap(tagName, HtmlHelper.AnonymousObjectToHtmlAttributes(data));
}

public static IDisposable TagWrap(this IHtmlHelper htmlHelper, string tagName, IDictionary<string, object> data)
{
    var tag = new TagBuilder(tagName);
    tag.MergeAttributes(data);

    htmlHelper.ViewContext.Writer.Write(tag.RenderStartTag());

    return new DisposableAction(() =>
        htmlHelper.ViewContext.Writer.Write(tag.RenderEndTag()));
}

Hilfsklasse zum Rendern des schließenden Tags bei Dispose

public class DisposableAction : IDisposable
{
    private readonly Action DisposeAction;

    public DisposableAction(Action action)
    {
        DisposeAction = action;
    }

    public void Dispose()
    {
        DisposeAction();
    }
}
Pavlo Neiman
quelle
0

Basierend auf Abtauungen beantworten Sie hier eine Anpassung, indem Sie eine objectanstelle von string:

    public static MvcHtmlString ConditionalAttr(this HtmlHelper helper, string attributeName, object value, Func<bool> condition)
    {
        if (string.IsNullOrEmpty(attributeName) || value == null)
        {
            return MvcHtmlString.Empty;
        }

        var render = condition != null ? condition() : true;

        return render ? 
            new MvcHtmlString($"{attributeName}=\"{HttpUtility.HtmlAttributeEncode(value.ToString())}\"") : 
            MvcHtmlString.Empty;
    }

Auf diese Weise müssen Sie Ihre anderen Datentypen nicht in Zeichenfolgen umwandeln, bevor Sie sie übergeben, um eine Ansicht zu speichern .ToString(). Es gibt einen Unterschied : Wenn Sie eine leere Zeichenfolge übergeben, wird dies weiterhin gerendert. Zum Beispiel:

@Html.ConditionalAttr("data-foo", "", () => Model.IsFooNeeded)

// Ouput:
data-foo=""
Spaark
quelle