asp.net mvc - tutorial - ¿Cómo crear concisamente atributos HTML opcionales con el motor de vista razorosa?
razor html (9)
Estoy buscando una forma de escribir el siguiente código con menos líneas de código (tal vez 5). Supongo que podría hacer lo mismo que la clase seleccionada, pero esta sintaxis de afeitar no se ve bonita.
<ul>
@foreach (var mi in Model.MenuItems) {
<li@(mi.Selected?" class=/"selected/"":null)>
@if (string.IsNullOrEmpty(mi.Title)) {
<a href="@mi.Href">@mi.Text</a>
} else {
<a href="@mi.Href" title="@mi.Title">@mi.Text</a>
}
</li>
}
</ul>
Solucionado en ASP.NET MVC 4
ver http://weblogs.asp.net/jgalloway/archive/2012/02/16/asp-net-4-beta-released.aspx
Representación de atributo condicional
Si tiene un atributo que podría ser nulo, en el pasado tuvo que hacer una comprobación nula para evitar escribir un atributo vacío, como este:
<div @{if (myClass != null) { <text>class="@myClass"</text> } }>Content</div>
Ahora Razor puede manejar eso automáticamente, así que puedes escribir el atributo. Si es nulo, el atributo no está escrito:
<div class="@myClass">Content</div>
Entonces, si @myClass es nulo, la salida es solo esta:
<div>Content</div>
Es realmente bastante simple y limpio:
<p @(cssClass != null) ? { class="@cssClass" }> Stuff and whatnot... </p>
Ese sería un buen candidato para el asistente HTML personalizado:
public static class HtmlExtensions
{
public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper, MenuItem mi)
{
var li = new TagBuilder("li");
if (mi.Selected)
{
li.AddCssClass("selected");
}
var a = new TagBuilder("a");
a.MergeAttribute("href", mi.Href);
if (!string.IsNullOrEmpty(mi.Title))
{
a.MergeAttribute("title", mi.Title);
}
a.SetInnerText(mi.Text);
return MvcHtmlString.Create(li.ToString());
}
}
y en su opinión:
<ul>
@foreach (var mi in Model.MenuItems) {
@Html.MenuItem(mi)
}
</ul>
o usando DisplayTemplates, ni siquiera necesita escribir un bucle:
<ul>
@Html.DisplayFor(x => x.MenuItems)
</ul>
He creado una clase HtmlAttribute encadenable y algunos métodos de extensión Html para permitir la sintaxis de Razor a continuación:
<ul>
@foreach (var mi in items) {
<li @Html.Css("selected", mi.Selected)>
<a href="@mi.Href" @Html.Attr("title", mi.Title)>@mi.Text</a>
</li>
}
</ul>
Aquí está la clase HtmlAttribute:
public class HtmlAttribute : IHtmlString
{
private string _InternalValue = String.Empty;
private string _Seperator;
public string Name { get; set; }
public string Value { get; set; }
public bool Condition { get; set; }
public HtmlAttribute(string name)
: this(name, null)
{
}
public HtmlAttribute( string name, string seperator )
{
Name = name;
_Seperator = seperator ?? " ";
}
public HtmlAttribute Add(string value)
{
return Add(value, true);
}
public HtmlAttribute Add(string value, bool condition)
{
if (!String.IsNullOrWhiteSpace(value) && condition)
_InternalValue += value + _Seperator;
return this;
}
public string ToHtmlString()
{
if (!String.IsNullOrWhiteSpace(_InternalValue))
_InternalValue = String.Format("{0}=/"{1}/"", Name, _InternalValue.Substring(0, _InternalValue.Length - _Seperator.Length));
return _InternalValue;
}
}
Información adicional: el "separador" se usa para encadenar varios valores para un atributo. Esto puede ser útil para múltiples nombres de clase css (use un espacio) o tal vez use String.Empty para construir un valor que dependa de múltiples condiciones (usando el método .Add ())
Y aquí están los métodos de ayuda de la extensión Html:
public static class Extensions
{
public static HtmlAttribute Css(this HtmlHelper html, string value)
{
return Css(html, value, true);
}
public static HtmlAttribute Css(this HtmlHelper html, string value, bool condition)
{
return Css(html, null, value, condition);
}
public static HtmlAttribute Css(this HtmlHelper html, string seperator, string value, bool condition)
{
return new HtmlAttribute("class", seperator).Add(value, condition);
}
public static HtmlAttribute Attr(this HtmlHelper html, string name, string value)
{
return Attr(html, name, value, true);
}
public static HtmlAttribute Attr(this HtmlHelper html, string name, string value, bool condition)
{
return Attr(html, name, null, value, condition);
}
public static HtmlAttribute Attr(this HtmlHelper html, string name, string seperator, string value, bool condition)
{
return new HtmlAttribute(name, seperator).Add(value, condition);
}
}
Avíseme si son útiles.
Gracias,
Sotavento
Para el caso de múltiples clases, utilizo este método de extensión simple:
public static MvcHtmlString If(this string text, bool condition) {
return new MvcHtmlString(condition ? text : string.Empty);
}
Y en la vista:
<div class="menuitem @("active".If(Model.Active))">
Quite la maquinilla de afeitar y use el motor de visualización Spark. ;)
Vea cuánto funcionan los atributos de HTML opcionales de simpiler aquí http://sparkviewengine.com/documentation/expressions#Conditionalattributeoutput
class
atributo de class
no sería renderizado por Razor si el valor es null
<a href="#nolink" class="@(categoryId == null ? "submenu-active": null)">All</a>
<ul>
@foreach (var mi in Model.MenuItems) {
<li@(mi.Selected?" class=/"selected/"":null)>
<a href="@mi.Href" @{if(!string.IsNullOrEmpty(mi.Title)) { <text>title="@mi.Title"</text>} }>@mi.Text</a>
</li>
}
</ul>
No lo he probado, pero analiza correctamente.
<ul>
@foreach (var mi in Model.MenuItems) {
<li@(Html.Raw((mi.Selected ? " class=/"selected/"" : null))>
<a href="@mi.Href">@mi.Text</a>
</li>
}
</ul>