Cómo agregar una clase "activa" a Html.ActionLink en ASP.NET MVC

128

Estoy tratando de agregar una clase "activa" a mi barra de navegación de arranque 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 dice que las etiquetas 'a' no deberían usarse en la barra de navegación, pero lo anterior es cómo creo que es la forma correcta de agregar una clase a un Html.ActionLink. ¿Hay otra forma (ordenada) de hacer esto?

Gillespie
fuente
3
el código que resuelve tiene class = active en él. ¿No es eso lo que dices que quieres en tu pregunta? Cómo usted tiene su código es cómo agrego clases
Matt corporal
no eres muy claro !!! No entiendo exactamente cuál es el problema al agregarlo a la navegación, a pesar de que tengo la sensación, la forma en que debería estar bien
JC Lizard
1
¿Cuál es el problema con el código resuelto? ¿Qué estás esperando? ¿Puedes ser más específico que "no parece funcionar"? Tu pregunta no es lo suficientemente clara como para ayudarte en este momento.
dom
Editado! lo siento, lo que quise decir es que la clase "activa" no se muestra en absoluto
Gillespie
2
Solo eché un vistazo a los documentos de Bootstrap y creo que debes agregar la activeclase al lielemento, no el a. Vea el primer ejemplo aquí: getbootstrap.com/components/#navbar
dom

Respuestas:

300

En Bootstrap, la activeclase debe aplicarse al <li>elemento y no al <a>. Vea el primer ejemplo aquí: http://getbootstrap.com/components/#navbar

La forma en que maneja su estilo de UI en función de lo que está activo o no tiene nada que ver con el ActionLinkasistente de ASP.NET MVC . Esta es la solución adecuada para seguir cómo se creó 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 manera de aplicar esa clase seleccionada automáticamente en función de la página actual en lugar de copiar el menú varias veces y hacerlo manualmente.

La forma más fácil es simplemente usar los valores contenidos ViewContext.RouteData, es decir, los valores Actiony Controller. Podríamos construir sobre lo que tiene 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á comenzando, lo dejaré así. ¡Mucha suerte aprendiendo ASP.NET MVC!


Edición tardía:

Esta pregunta parece estar obteniendo un poco de tráfico, así que pensé que agregaría una solución más elegante usando una HtmlHelperextensión.

Editar 24/03/2015: Tuve que reescribir este método para permitir que múltiples acciones y controladores desencadenaran el comportamiento seleccionado, así como el manejo cuando se llama al método desde una vista parcial de acción secundaria, ¡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;
}

Funciona con .NET Core:

public static string IsSelected(this IHtmlHelper htmlHelper, string controllers, string actions, string cssClass = "selected")
{
    string currentAction = htmlHelper.ViewContext.RouteData.Values["action"] as string;
    string currentController = htmlHelper.ViewContext.RouteData.Values["controller"] as string;

    IEnumerable<string> acceptedActions = (actions ?? currentAction).Split(',');
    IEnumerable<string> acceptedControllers = (controllers ?? currentController).Split(',');

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Uso de la 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>
dom
fuente
Gracias, como mencioné, así es como lo tenía originalmente, pero esperaba tener un método en todo mi código para cambiar la clase "activa" entre los objetos seleccionados.
Gillespie
2
@Gillespie no te preocupes! Edité mi respuesta para agregar información que podría ayudarlo un poco más.
dom
55
Con respecto a la primera edición, en realidad funcionó solo para la página de índice. Parece que la razón es que cuando estaba haciendo la comparación, falló ya que ViewContext.RouteData.Values ​​["Action"] no devuelve un objeto de tipo String (aún no sé cómo funcionó para la primera página ...) . Cuando cambié todos los ViewContext.RouteData.Values ​​["Action"] a ViewContext.RouteData.Values ​​["Action"]. ToString (), funcionó para todas las páginas. Es posible que desee agregar esto en su solución en caso de que alguien experimente el mismo problema.
usuario3281466
2
@LonelyPixel, ¿tal vez esta respuesta te funcione?
dom
1
Para usuarios de VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Inicio "," Índice "," Inicio ") </li>
Andrea Antonangeli
28

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>
Profe
fuente
1
Esta es una extensión bellamente eficiente. Funciona perfectamente y es bastante elegante. Felicitaciones a usted, profesor! Mi única queja es con el role="presentation", que no es del todo apropiado para un menú de navegación principal ( john.foliot.ca/aria-hidden/#pr ). Una lista desordenada es en gran medida un contenedor apropiado para un conjunto relacionado de enlaces, ya que los agrupa de una manera lógica.
René Kåbis
@ René Kåbis es para la navegación de arranque getbootstrap.com/components/#nav-tabs
Prof
1
Esto no funciona cuando el usuario ingresa manualmente la url en minúscula o mayúscula, por ejemplo. " domain.com/Login " y " domain.com/LOGIN ". Para la solución, var str = String.Format("<li role=\"presentation\"{0}>{1}</li>", currentAction.toLower().Equals(action.toLower(), StringComparison.InvariantCulture) && currentController.toLower().Equals(controller.toLower(), StringComparison.InvariantCulture) ? " class=\"active\"" : String.Empty, html.ActionLink(text, action, controller).ToHtmlString() );
sky91
20

Logré hacer esto agregando un parámetro de vista de bolsa en asp.net mvc. Aqui que he hecho

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

Damith
fuente
Solución simple y fácil.
Japes Sophey
13

Puede llegar 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 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 referencia de http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html

Virag Dilip Desai
fuente
1
Solución muy simple y elegante. Hice algunas mejoras aquí gist.github.com/jean-rakotozafy/… para resaltar un menú para todas las acciones del controlador.
Zan RAKOTO
5

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 al controlador de la vista.

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

Luego, 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 sí); por lo tanto, no se muestra nada, ni siquiera class = "". Creo que esto es más limpio tanto para la mantenibilidad como para la limpieza. Siempre tiendo a dejar la lógica fuera de la vista tanto como puedo.

mapussah
fuente
4

Teniendo en cuenta lo que Damith publicó, me gusta pensar que solo puede calificar como activo por el Viewbag.Title (la mejor práctica es completar esto en sus páginas de contenido permitiendo que su _Layout.cshtmlpágina mantenga sus barras de enlaces). También tenga en cuenta que si está utilizando elementos de 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>
Rafe Smith
fuente
Limpio y eficiente!
mggluscevic
3

He modificado de Dom respuesta "no es bonito" y lo hizo más feo. A veces, dos controladores tienen los nombres de acción 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>
DesarrolladorDan
fuente
3

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, qué 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="https://stackoverflow.com/MgtCustomer/Index"]').closest('li').addClass('active active-menu');
        });
</script>
atik sarker
fuente
3

Esta solución es simple para Asp.net MCV 5.

  1. Crea una clase estática, por ejemplo Utilitarios.cs.

  2. 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 "";
    }
  3. llama 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>
Deyvi Javier Saavedra García
fuente
3

ASP.NET Core y Bootstrap 4

La respuesta más actualizada

He reelaborado la solución ordenada de @crush para una forma actualizada, compatible con ASP.NET Core y Bootstrap 4 para resolver este problema basado en un IHtmlHelpermétodo de extensión:

public static class LinkExtensions
{
    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        var routeData = html.ViewContext.RouteData;
        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        using (var writer = new StringWriter())
        {
            writer.WriteLine($"<li class='nav-item {(active ? "active" : "")}'>");
            html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes).WriteTo(writer, HtmlEncoder.Default);
            writer.WriteLine("</li>");
            return new HtmlString(writer.ToString());
        }
    }
}

Uso

<nav class="navbar">
    <div class="collapse navbar-collapse">
        <ul class="navbar-nav">
            @Html.ActiveActionLink("Home", "Index", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("About", "About", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("Contact", "Contact", "TimeTracking", null, new { @class = "nav-link" })
        </ul>
    </div>
</nav>
WoIIe
fuente
1
Muy buena solucion. En su ejemplo, ¿cómo puedo configurar 'Contacto' como activo por defecto?
MD Suman Kabir
1
Gracias. Lo bueno es que no necesita establecer un elemento activo. Tan pronto como se visite la página 'Contacto', ActiveActionLink()se aplicará la clase activa a <li>:-)
WoIIe
¿Dónde está el área de verificación?
Mohammad
@Mohammad no entiendo. ¿Podría por favor elaborar su pregunta?
WoIIe
en la clase LinkExtensions no obtuvo área de routeData!
Mohammad el
3

Fácil ASP.NET Core 3.0 y TagHelpers

[HtmlTargetElement("li", Attributes = "active-when")]
public class LiTagHelper : TagHelper
{
    public string ActiveWhen { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContextData { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (ActiveWhen == null)
            return;

        var targetController = ActiveWhen.Split("/")[1];
        var targetAction = ActiveWhen.Split("/")[2];

        var currentController = ViewContextData.RouteData.Values["controller"].ToString();
        var currentAction = ViewContextData.RouteData.Values["action"].ToString();

        if (currentController.Equals(targetController) && currentAction.Equals(targetAction))
        {
            if (output.Attributes.ContainsName("class"))
            {
                output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
            }
            else
            {
                output.Attributes.SetAttribute("class", "active");
            }
        }
    }
}

Incluir en su _ViewImports.cs:

@addTagHelper *, YourAssemblyName

Uso:

 <li active-when="/Home/Index">
Guilherme V.
fuente
2

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>

-


fuente
Esto no funcionará si hay los mismos nombres de acción en dos controladores diferentes. Pruébelo con los controladores Home y About con la acción Index.
hyde
podría desactivar el servidor de funciones en la máquina de afeitar como: @functions { public bool IsActive(string action, string controller) { var actionRoute = ViewContext.RouteData.Values["Action"].ToString(); var controlRoute = ViewContext.RouteData.Values["Controller"].ToString(); return controller.Equals(controlRoute)&& actionRoute.Equals(actionRoute); } }y uso: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung
2

También podemos crear UrlHelperdesde RequestContext que podemos obtener de MvcHandler. Por lo tanto, creo que alguien que quiera mantener esta lógica en las plantillas de Razor de la siguiente manera sería útil:

  1. En la raíz del proyecto, cree una carpeta llamada AppCode .
  2. Crea un archivo allí llamado HtmlHelpers.cshtml
  3. 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>
         }   
    }
  4. Entonces podemos usar en nuestras vistas así:

    @HtmlHelpers.MenuItem("Default", "Home")

Espero que ayude a alguien.

Oleksii Aza
fuente
Esto es realmente genial. ¿Hay algún inconveniente de rendimiento aquí?
aplastar
@crush, no lo he medido, pero esperaría que tenga un bajo impacto en el rendimiento porque creo que el marco utiliza una lógica similar para crear lo UrlHelperque tienes Controller.Url. Lo único es que probablemente no deseamos ejecutar la creación UrlHelperpara cada llamada, por MenuItemlo que podemos aplicar una marca de guardarlo en Elementos HttpContext después de la primera llamada al ayudante, por lo que lo hacemos solo una vez por solicitud.
Oleksii Aza
2

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" : "";
}

luego uso

 @Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})
henoc salinas
fuente
2

Creé una HtmlHelperextensión que agrega un ActiveActionLinkmétodo para aquellos de ustedes que desean agregar la clase "activa" al enlace en sí en lugar del enlace que lo <li>rodea.


public static class LinkExtensions
{
    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        const string activeClassName = "active";

        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        if (active)
        {
            var @class = (string)htmlAttributes["class"];

            htmlAttributes["class"] = string.IsNullOrEmpty(@class)
                ? activeClassName
                : @class + " active";
        }

        var link = html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        return link;
    }
}

El uso es el siguiente:

@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })
Persona especial
fuente
1

la respuesta de @dombenoit funciona. Aunque introduce algún código para mantener. Mira 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 de .SetLinksActiveByControllerAndAction() método.

Si se pregunta qué hace posible esta sintaxis, consulte TwitterBootstrapMVC

Dmitry Efimenko
fuente
Gracias por la respuesta Dmitry, estoy probando TwitterBootstrapMVC
Gillespie
1

También estaba buscando una solución y jQuery me ayudó bastante. Primero, necesitas dar 'id' a tus <li>elementos.

<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é <li>elemento debe 'seleccionarse' en su vista.

@section Scripts{
    <script type="text/javascript">
        $('#listguides').addClass('selected');
    </script>
}

Nota: debe tener @RenderSection("scripts", required: false)en su página de diseño, justo antes de la </body>etiqueta para agregar esa sección.

Doğa Gençer
fuente
1

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.

Osama
fuente
0

si es que no se muestra en absoluto, la razón es que necesita dos signos @:

@@class

PERO, creo que es posible que necesite tener la clase activa en la etiqueta "li" y no en la etiqueta "a". de acuerdo con los documentos de 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>
JC Lizard
fuente
La clase @@ arroja un error, originalmente tenía su ejemplo de código anterior, que funciona, pero no es exactamente como Actionlinks "debería" ser.
Gillespie
editado el @@ no es obligatorio. tienes que poner la clase en el EA
JC Lizard
0

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 la función auxiliar 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/

Ganesh Todkar
fuente
0

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 de utilidad.

Nota: Este paquete nuget es mi primer paquete. Entonces, si ve un error, por favor envíe sus comentarios. Gracias.

  1. Instale el paquete o descargue el código fuente y agregue su proyecto

    -Install-Package Betalgo.MvcMenuNavigator
  2. Agregue sus páginas a una enumeración

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Coloque el filtro en la parte superior de su 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();
        }
    }
  4. 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

Tolga Kayhan
fuente
0

Creo que aquí hay un código más pequeño y limpio para hacer que el menú seleccionado esté "activo":

 <ul class="navbar-nav mr-auto">
                <li class="nav-item @Html.IfSelected("Index")">
                    <a class="nav-link" href="@Url.Action("Index", "Home")">Home</a>
                </li>
                <li class="nav-item @Html.IfSelected("Controls")">
                    <a class="nav-link" href="@Url.Action("Controls", "Home")">MVC Controls</a>
                </li>
                <li class="nav-item @Html.IfSelected("About")">
                    <a class="nav-link" href="@Url.Action("About", "Home")">About</a>
                </li>
</ul>

 public static string IfSelected(this HtmlHelper html, string action)
        {
            return html
                       .ViewContext
                       .RouteData
                       .Values["action"]
                       .ToString() == action
                            ? " active"
                            : "";
        }
Gabriel Marius Popescu
fuente
Agradable, aunque probablemente deba extenderse para el controlador y el área en algunos casos
planetClaire
-1

He hecho una combinación de las respuestas anteriores e hice mi solución.

Entonces..

Primero en el razor block cree una variable de cadena que contendrá el valor del nombre del controlador y la acción que llama el usuario.

    @{
        string controllerAction =  ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString(); 
    }

Luego use la combinación de HTML y código 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.

Nihad Delic
fuente
-1

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 mejor manera puede ser agregar un método de extensión Html para devolver la ruta actual a comparar con el enlace

Mudasar Rauf
fuente
-1

Hice esto:

Hizo un ayudante en la vista parcial del menú

 @helper RouterLink(string action, string controller)
{
    var IsActive = ViewContext.RouteData.Values["Controller"].ToString() == controller && ViewContext.RouteData.Values["Action"].ToString() == action;
    <text>href="@Url.Action(action, controller)"</text>if (IsActive){ <text>class="active"</text>}
}

Luego lo usé en la etiqueta de anclaje de esta manera:

<li><a @RouterLink("Index","Home")>Home</a></li>

Mi aplicación no tenía áreas, pero también se puede incluir como otra variable en la función auxiliar. Y tuve que pasar la clase activa a la etiqueta de anclaje en mi opinión. Pero litambién se puede configurar así.

Anup Sharma
fuente
1
Verá, el voto negativo realmente no ayuda si no menciona la razón.
Anup Sharma