Бритва ASP.NET MVC: умовний атрибут у HTML


83

Наведений нижче код не здається чистим. Будь-яка пропозиція щодо вдосконалення коду?

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

Можливо, створити власний помічник HTML, який видавав би LI з дочірніми елементами посилання?
Нік Борк

Відповіді:


142

MVC має вбудовані атрибути ...

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

Якщо @myClass має значення null, він просто не використовуватиме атрибут взагалі ...

Я знаю, що це може не зовсім вирішити вашу поточну проблему, але це заслуговує на увагу!

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


Будьте обережні, щоб ім'я вашого класу не було "активним", інакше у вас буде атрибут класу входу. Не знаю, чому.
ScottE

3
Чи є спосіб досягти такої самої поважної поведінки при виклику помічників html, що передають анонімний htmlPropertiesоб'єкт? Наприклад, я хочу умовно передати атрибут disabled, наприклад @Html.TextBoxFor(lambda, new { disabled = condition ? true : null }), але це все одно відображає, disabled=""коли disabledбуло null, що є тим самим, що і рендеринг, disabled="anything"оскільки disabledактивне, коли атрибут присутній, незалежно від значення. Знайдено stackoverflow.com/q/7978137/11683 за темою, але чи є сьогодні кращі способи, цікаво?
GSerg

1
Примітка сторони: «дані -...» атрибути не можуть бути умовними і зробити пусте значення навіть для нуля ( stackoverflow.com/questions/13267619 / ... )
Олексій Левенко

75
<li class="@(ViewBag.pagename == "Business details" ? "active" : null)">  

Вам слід замінити вбудований текст style="..."на окреме ім'я класу і використовувати там такий самий синтаксис.

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


1
Гарний, набагато чистіший за інші варіанти (крім опції Razor 2.0).
ctrlplusb

21

Я використовую невеликий допоміжний метод, який умовно додасть атрибут, якщо значення не є порожнім, і, якщо визначено, коли вираз булевої функції має значення 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;
}

Після визначення я можу використовувати цей метод у своїх представленнях Razor:

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

Наведений вище код відображатиметься, <li class="new">...</li>якщо example.isNew == true, якщо ні, опускатиме весь classатрибут.


1
Дуже елегантний спосіб зробити це. Але замість Func<bool>лямбди я віддаю перевагу простому bool?параметру, оскільки він простіший:<li @Html.Attr("class", "new", example.isNew)>
T-moty

Мені подобається такий підхід, тому що багато користувацьких JavaScript у моїй програмі все одно будуть працювати, коли ім’я атрибута все ще є. І принаймні це не змушує вас повторювати один і той же div через різницю атрибутів. Дякую!
Бен Сьюардс,


0

Підхід за допомогою методу розширення TagWrap. Код для вашого запитання буде виглядати так:

@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

використання 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()));
}

Допоміжний клас, який використовується для візуалізації закриваючого тегу на Dispose

public class DisposableAction : IDisposable
{
    private readonly Action DisposeAction;

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

    public void Dispose()
    {
        DisposeAction();
    }
}

0

На основі розморожування дайте відповідь тут на адаптацію, objectзамість 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;
    }

Таким чином, вам не потрібно перетворювати інші типи даних у рядки, перш ніж передавати їх, зберігаючи п’ятку .ToString(). Існує різниця в тому, що передача порожнього рядка все одно відображатиметься. Як приклад:

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

// Ouput:
data-foo=""

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.