template - Cómo agregar una clase "activa" a Html.ActionLink en ASP.NET MVC
bootstrap form with asp net (20)
Estoy tratando de agregar una clase "activa" a mi barra de navegación bootstrap en MVC, pero lo siguiente no muestra la clase activa cuando se escribe así:
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home", null, new {@class="active"})</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
Esto resuelve lo que parece una clase formateada correctamente, pero no funciona:
<a class="active" href="/">Home</a>
En la documentación de Bootstrap, indica que las etiquetas ''a'' no se deben usar en la barra de navegación, pero lo anterior es la forma correcta de agregar una clase a Html.ActionLink. ¿Hay alguna otra forma (ordenada) en que pueda hacer esto?
Agregue ''.ToString'' para mejorar la comparación en ASP.NET MVC
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
-
Decidí hacer esto agregando un parámetro de bolsa de vista en asp.net mvc. Aquí lo que he hecho
Se agregó ViewBag.Current = "Scheduler";
como parámetro en cada página
En la página de diseño
<ul class="nav navbar-nav">
<li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action("Index","Scheduler")" target="_self">Scheduler</a></li>
</ul>
Esto resolvió mi problema.
En Bootstrap, la clase active
debe aplicarse al elemento <li>
y no a <a>
. Vea el primer ejemplo aquí: getbootstrap.com/components/#navbar
La forma en que manejas tu estilo de interfaz de usuario según lo que está activo o no tiene nada que ver con el asistente de ActionLink
ASP.NET MVC. Esta es la solución adecuada para seguir cómo se construyó el marco Bootstrap.
<ul class="nav navbar-nav">
<li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
Editar:
Como lo más probable es que reutilice su menú en varias páginas, sería inteligente tener una forma de aplicar esa clase seleccionada de forma automática en función de la página actual en lugar de copiar el menú varias veces y hacerlo manualmente.
La manera más fácil es simplemente usar los valores contenidos en ViewContext.RouteData
, es decir, los valores de Action
y Controller
. Podríamos construir sobre lo que tienes actualmente con algo como esto:
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
No es bonito en el código, pero hará el trabajo y le permitirá extraer su menú en una vista parcial si lo desea. Hay maneras de hacer esto de una manera mucho más limpia, pero como recién estás comenzando, lo dejo así. ¡La mejor de las suertes aprendiendo ASP.NET MVC!
Edición tardía:
Parece que esta pregunta está recibiendo un poco de tráfico, así que pensé en utilizar una extensión más elegante usando una extensión HtmlHelper
.
Editar 24/03/2015: Tuve que volver a escribir este método para permitir múltiples acciones y controladores que desencadenan el comportamiento seleccionado, así como el manejo para cuando se llama al método desde una vista parcial de acción infantil, ¡pensé que compartiría la actualización!
public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = "selected")
{
ViewContext viewContext = html.ViewContext;
bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;
if (isChildAction)
viewContext = html.ViewContext.ParentActionViewContext;
RouteValueDictionary routeValues = viewContext.RouteData.Values;
string currentAction = routeValues["action"].ToString();
string currentController = routeValues["controller"].ToString();
if (String.IsNullOrEmpty(actions))
actions = currentAction;
if (String.IsNullOrEmpty(controllers))
controllers = currentController;
string[] acceptedActions = actions.Trim().Split('','').Distinct().ToArray();
string[] acceptedControllers = controllers.Trim().Split('','').Distinct().ToArray();
return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
cssClass : String.Empty;
}
Uso de muestra:
<ul>
<li class="@Html.IsSelected(actions: "Home", controllers: "Default")">
<a href="@Url.Action("Home", "Default")">Home</a>
</li>
<li class="@Html.IsSelected(actions: "List,Detail", controllers: "Default")">
<a href="@Url.Action("List", "Default")">List</a>
</li>
</ul>
Espero que esto ayude, a continuación se muestra cómo puede ser su menú:
<ul class="nav navbar-nav">
<li><a href="@Url.Action("Index", "Home")" class="@IsMenuSelected("Index","Home", "active")">Home</a></li>
<li><a href="@Url.Action("About", "Home")" class="@IsMenuSelected("About", "Home", "active")">About</a></li>
<li><a href="@Url.Action("Contact", "Home")" class="@IsMenuSelected("Contact", "Home", "active")">Contact</a></li>
</ul>
Y agregue debajo de la función auxiliar de MVC debajo de la etiqueta html.
@helper IsMenuSelected(string actionName, string controllerName, string className)
{
var conname = ViewContext.RouteData.Values["controller"].ToString().ToLower();
var actname = ViewContext.RouteData.Values["action"].ToString().ToLower();
if (conname == controllerName.ToLower() && actname == actionName.ToLower())
{
@className;
}
}
Remití la respuesta de http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/
Esta solución es simple para Asp.net MCV 5.
Crea una clase estática, por ejemplo,
Utilitarios.cs
.Dentro de la clase crea un método estático:
public static string IsLinkActive(this UrlHelper url, string action, string controller) { if (url.RequestContext.RouteData.Values["controller"].ToString() == controller && url.RequestContext.RouteData.Values["action"].ToString() == action) { return "active"; } return ""; }
llamar así
<ul class="sidebar-menu" data-widget="tree"> <li class="header">HEADER</li> <li class="@Url.IsLinkActive("Index", "Home")"> <a href="@Url.Action("Index", "Home")"><i class="fa fa-link"></i> <span>Home</span></a> </li> <li class="@Url.IsLinkActive("About", "Home")"> <a href="@Url.Action("About", "Home")"><i class="fa fa-link"></i><span>About</span></a> </li> </ul>
Extensión:
public static MvcHtmlString LiActionLink(this HtmlHelper html, string text, string action, string controller)
{
var context = html.ViewContext;
if (context.Controller.ControllerContext.IsChildAction)
context = html.ViewContext.ParentActionViewContext;
var routeValues = context.RouteData.Values;
var currentAction = routeValues["action"].ToString();
var currentController = routeValues["controller"].ToString();
var str = String.Format("<li role=/"presentation/"{0}>{1}</li>",
currentAction.Equals(action, StringComparison.InvariantCulture) &&
currentController.Equals(controller, StringComparison.InvariantCulture) ?
" class=/"active/"" :
String.Empty, html.ActionLink(text, action, controller).ToHtmlString()
);
return new MvcHtmlString(str);
}
Uso:
<ul class="nav navbar-nav">
@Html.LiActionLink("About", "About", "Home")
@Html.LiActionLink("Contact", "Contact", "Home")
</ul>
He hecho una combinación de respuestas arriba e hice mi solución.
Asi que..
Primero en el bloque de afeitar, cree una variable de cadena que contendrá el valor de nombre del controlador y la acción que el usuario llama.
@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
}
Luego use una combinación de código HTML y Razor:
<ul class="nav navbar-nav">
<li class="@(controllerAction == "HomeIndex" ? "active" : "" )">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(controllerAction == "AboutIndex" ? "active" : "" )">@Html.ActionLink("About", "Index", "About")</li>
<li class="@(controllerAction == "HomeContact" ? "active" : "" )">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
Creo que esto es bueno porque no necesita acceder a "ViewContext.RouteData.Values" cada vez para obtener el nombre del controlador y el nombre de la acción.
Me di cuenta de que este problema era un problema común para algunos de nosotros, así que publiqué mi propia solución usando el paquete nuget. A continuación puedes ver cómo funciona. Espero que sea útil.
Nota: Este paquete nuget es mi primer paquete. Entonces, si ve un error, por favor envíe sus comentarios. Gracias.
Instale el paquete o descargue el código fuente y agregue su proyecto
-Install-Package Betalgo.MvcMenuNavigator
Agregue sus páginas a una enumeración
public enum HeaderTop { Dashboard, Product } public enum HeaderSub { Index }
Pon el filtro en la parte superior de tu Controllor o Acción
[MenuNavigator(HeaderTop.Product, HeaderSub.Index)] public class ProductsController : Controller { public async Task<ActionResult> Index() { return View(); } [MenuNavigator(HeaderTop.Dashboard, HeaderSub.Index)] public async Task<ActionResult> Dashboard() { return View(); } }
Y úsalo en tu diseño de encabezado como este
@{ var headerTop = (HeaderTop?)MenuNavigatorPageDataNavigatorPageData.HeaderTop; var headerSub = (HeaderSub?)MenuNavigatorPageDataNavigatorPageData.HeaderSub; } <div class="nav-collapse collapse navbar-collapse navbar-responsive-collapse"> <ul class="nav navbar-nav"> <li class="@(headerTop==HeaderTop.Dashboard?"active selected open":"")"> <a href="@Url.Action("Index","Home")">Dashboard</a> </li> <li class="@(headerTop==HeaderTop.Product?"active selected open":"")"> <a href="@Url.Action("Index", "Products")">Products</a> </li> </ul>
Más información: https://github.com/betalgo/MvcMenuNavigator
Me gustaría proponer esta solución que se basa en la primera parte de la respuesta de Dom.
Primero definimos dos variables, "acción" y "controlador" y las usamos para determinar el enlace activo:
{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}
Y entonces:
<ul class="nav navbar-nav">
<li class="@((controller == "Home" && action == "Index") ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@((controller == "Home" && action == "About") ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@((controller == "Home" && action == "Contact") ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
Ahora se ve mejor y no necesita soluciones más complejas.
Mi solución a este problema es
<li class="@(Context.Request.Path.Value.ToLower().Contains("about") ? "active " : "" ) nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="About">About</a>
</li>
Una forma mejor puede ser agregar un método de extensión Html para devolver la ruta actual para compararla con el enlace
Puede intentar esto: en mi caso estoy cargando el menú de la base de datos basado en el acceso basado en roles, escriba el código en cada vista que menú desea activar en función de su vista.
<script type="text/javascript">
$(document).ready(function () {
$(''li.active active-menu'').removeClass(''active active-menu'');
$(''a[href="/MgtCustomer/Index"]'').closest(''li'').addClass(''active active-menu'');
});
</script>
Puede ser un poco tarde Pero espero que esto ayude.
public static class Utilities
{
public static string IsActive(this HtmlHelper html,
string control,
string action)
{
var routeData = html.ViewContext.RouteData;
var routeAction = (string)routeData.Values["action"];
var routeControl = (string)routeData.Values["controller"];
// both must match
var returnActive = control == routeControl &&
action == routeAction;
return returnActive ? "active" : "";
}
}
Y el uso de la siguiente manera:
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class=''@Html.IsActive("Home", "Index")''>
@Html.ActionLink("Home", "Index", "Home")
</li>
<li class=''@Html.IsActive("Home", "About")''>
@Html.ActionLink("About", "About", "Home")
</li>
<li class=''@Html.IsActive("Home", "Contact")''>
@Html.ActionLink("Contact", "Contact", "Home")
</li>
</ul>
</div>
Obtuve una referencia de http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html
Sé que esta pregunta es antigua, pero me gustaría agregar mi voz aquí. Creo que es una buena idea dejar el conocimiento de si un enlace está activo o no para el controlador de la vista.
Solo establecería un valor único para cada vista en la acción del controlador. Por ejemplo, si quisiera activar el enlace de la página de inicio, haría algo como esto:
public ActionResult Index()
{
ViewBag.Title = "Home";
ViewBag.Home = "class = active";
return View();
}
Entonces, en mi opinión, escribiré algo como esto:
<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>
Cuando navega a una página diferente, diga Programas, ViewBag.Home no existe (en cambio ViewBag.Programs lo hace); por lo tanto, no se representa nada, ni siquiera class = "". Creo que esto es más limpio tanto para la facilidad de mantenimiento y la limpieza. Tiendo a querer siempre dejar la lógica fuera de la vista tanto como pueda.
También estaba buscando una solución y jQuery ayudó bastante. En primer lugar, debe dar ''id'' a sus elementos <li>
.
<li id="listguides"><a href=''/Guides/List''>List Guides</a></li>
Después de hacer esto en su página de diseño, puede decirle a jQuery qué elemento <li>
debe ser ''seleccionado'' en su vista.
@section Scripts{
<script type="text/javascript">
$(''#listguides'').addClass(''selected'');
</script>
}
Nota: Necesita tener @RenderSection("scripts", required: false)
en su página de diseño, justo antes de la etiqueta </body>
para agregar esa sección.
También podemos crear UrlHelper
partir de RequestContext que podemos obtener de MvcHandler. Por lo tanto, creo que alguien que quiera mantener esta lógica en las plantillas Razor de la siguiente manera sería útil:
- En la raíz del proyecto, cree una carpeta llamada
AppCode
. - Crea un archivo llamado
HtmlHelpers.cshtml
Crea un ayudante allí:
@helper MenuItem(string action, string controller) { var mvcHandler = Context.CurrentHandler as MvcHandler; if (mvcHandler != null) { var url = new UrlHelper(mvcHandler.RequestContext); var routeData = mvcHandler.RequestContext.RouteData; var currentAction = routeData.Values["action"].ToString(); var currentController = routeData.Values["controller"].ToString(); var isCurrent = string.Equals(currentAction, action, StringComparison.InvariantCultureIgnoreCase) && string.Equals(currentController, controller, StringComparison.InvariantCultureIgnoreCase); <div class="@(isCurrent ? "active" : "")"> <div>@url.Action(action, controller)</div> </div> } }
Entonces podemos usar en nuestros puntos de vista de esta manera:
@HtmlHelpers.MenuItem("Default", "Home")
Espero que ayude a alguien.
Teniendo en cuenta lo que publicó Damith, me gusta pensar que simplemente puede calificar activo por el Viewbag.Title (la mejor práctica es rellenar esto en sus páginas de contenido permitiendo que su página _Layout.cshtml
contenga sus barras de vínculos). También tenga en cuenta que si está utilizando elementos del submenú también funciona bien:
<li class="has-sub @(ViewBag.Title == "Dashboard 1" || ViewBag.Title == "Dashboard 2" ? "active" : "" )">
<a href="javascript:;">
<b class="caret"></b>
<i class="fa fa-th-large"></i>
<span>Dashboard</span>
</a>
<ul class="sub-menu">
<li class="@(ViewBag.Title == "Dashboard 1" ? "active" : "")"><a href="index.html">Dashboard v1</a></li>
<li class="@(ViewBag.Title == "Dashboard 2" ? "active" : "")"><a href="index_v2.html">Dashboard v2</a></li>
</ul>
</li>
es posible con una función lambda
@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}
entonces el uso
@Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})
la respuesta de @dombenoit funciona. Aunque introduce algún código para mantener. Compruebe esta sintaxis:
using (var nav = Html.Bootstrap().Begin(new Nav().Style(NavType.NavBar).SetLinksActiveByControllerAndAction()))
{
@nav.ActionLink("Link 1", "action1")
@nav.ActionLink("Link 2", "action2")
@nav.Link("External Link", "#")
}
Observe el uso del método .SetLinksActiveByControllerAndAction()
.
Si se pregunta qué hace posible esta sintaxis, consulte TwitterBootstrapMVC
si no se muestra, la razón es que necesita dos @ signo:
@@class
PERO, creo que es posible que necesite tener la clase activa en la etiqueta "li", no en la etiqueta "a". de acuerdo con los documentos bootstrap ( http://getbootstrap.com/components/#navbar-default ):
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#">Profile</a></li>
<li><a href="#">Messages</a></li>
</ul>
por lo tanto, su código será:
<ul class="nav navbar-nav">
<li class="active">@Html.ActionLink("Home", "Index", "Home", null)</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
dom respuesta "no bonita" de dom y la hice más fea. A veces, dos controladores tienen los nombres de acciones en conflicto (es decir, índice), así que hago esto:
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "HomeIndex" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "AboutIndex" ? "active" : "")">@Html.ActionLink("About", "Index", "About")</li>
<li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "ContactHome" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>