Como adicionar a classe "ativa" ao Html.ActionLink no asp.net MVC

128

Estou tentando adicionar uma classe "ativa" à minha barra de navegação de inicialização no MVC, mas o seguinte não mostra a classe ativa quando escrita assim:

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

Isso resolve o que parece uma classe formatada corretamente, mas não funciona:

<a class="active" href="/">Home</a>

Na documentação do Bootstrap, ele afirma que as tags 'a' não devem ser usadas na barra de navegação, mas acima é como acredito que seja a maneira correta de adicionar uma classe a um Html.ActionLink. Existe outra maneira (organizada) de fazer isso?

Gillespie
fonte
3
o código que resolve tem class = active nele. Não é isso que você diz que quer na sua pergunta? Como você tem o seu código é como eu adicionar classes
Matt corporal
você não é muito claro !!! Eu não entendo exatamente qual é o problema em adicioná-lo ao nav, mesmo que eu tenha um pressentimento de que o modo como está deve ser bom
JC Lizard
1
Qual é o problema com o código resolvido? O que você está esperando? Você pode ser mais específico do que "parece não funcionar"? Sua pergunta não é clara o suficiente para ajudá-lo agora.
dom
Editado! desculpe, o que eu quis dizer foi que a classe "ativa" não está aparecendo nada
Gillespie
2
Apenas olhei os documentos do Bootstrap e acho que você precisa adicionar a activeclasse ao lielemento, não o a. Veja o primeiro exemplo aqui: getbootstrap.com/components/#navbar
dom

Respostas:

300

No Bootstrap, a activeclasse precisa ser aplicada ao <li>elemento e não ao <a>. Veja o primeiro exemplo aqui: http://getbootstrap.com/components/#navbar

A maneira como você lida com o estilo da interface do usuário com base no que está ativo ou não tem nada a ver com o ActionLinkassistente do ASP.NET MVC . Esta é a solução adequada para acompanhar como a estrutura do Bootstrap foi criada.

<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 você provavelmente estará reutilizando seu menu em várias páginas, seria inteligente aplicar uma classe selecionada automaticamente com base na página atual, em vez de copiar o menu várias vezes e fazê-lo manualmente.

A maneira mais fácil é usar apenas os valores contidos em ViewContext.RouteData, ou seja, os Actione Controllervalores. Podemos desenvolver o que você tem atualmente com algo assim:

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

Não é bonito no código, mas fará o trabalho e permitirá que você extraia seu menu em uma exibição parcial, se quiser. Existem maneiras de fazer isso de uma maneira muito mais limpa, mas como você está apenas começando, deixarei por isso. Boa sorte ao aprender o ASP.NET MVC!


Edição tardia:

Esta questão parece estar recebendo um pouco de tráfego, então imaginei que lançaria uma solução mais elegante usando uma HtmlHelperextensão.

Editar 24-03-2015: tive que reescrever esse método para permitir várias ações e controladores acionando o comportamento selecionado, além de lidar com quando o método é chamado a partir de uma exibição parcial de ação filho, pensei em compartilhar a atualização!

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 com o .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 da amostra:

<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
fonte
Obrigado, como eu mencionei, foi assim que o fiz originalmente, mas eu esperava ter um método em todo o meu código para alterar a classe "ativa" entre os objetos selecionados.
precisa
2
@Gillespie não se preocupe! Editei minha resposta para adicionar algumas informações que podem ajudá-lo um pouco mais.
dom
5
Com relação à primeira edição, ele realmente funcionou apenas para a página Índice. Parece que o motivo é que, ao fazer a comparação, ela falhou, pois ViewContext.RouteData.Values ​​["Action"] não retorna um objeto do tipo String (ainda não sabe como funcionou na primeira página ....) . Quando alterei todos os ViewContext.RouteData.Values ​​["Action"] para ViewContext.RouteData.Values ​​["Action"]. ToString (), funcionou para todas as páginas. Talvez você queira adicionar isso à sua solução, caso alguém tenha o mesmo problema.
user3281466
2
@LonelyPixel talvez essa resposta funcione para você?
dom
1
Para usuários do VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Página inicial "," Índice "," Página inicial ") </li> #
Andrea Antonangeli 24/16
28

Extensão:

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>
Prof
fonte
1
Esta é uma extensão lindamente eficiente. Funciona perfeitamente e é bastante elegante. Tiremos o chapéu, Prof! Minha única queixa é com o role="presentation", que não é de todo apropriado para um menu de navegação principal ( john.foliot.ca/aria-hidden/#pr ). Uma lista não ordenada é muito um contêiner apropriado para um conjunto de links relacionados, pois os agrupa de maneira lógica.
René Kåbis 28/04
@ René Kåbis it to bootstrap naigation getbootstrap.com/components/#nav-tabs
Prof
1
Isso não está funcionando quando o usuário insere manualmente o URL em letras minúsculas ou maiúsculas, por exemplo. " domain.com/Login " e " domain.com/LOGIN ". Para a solução, 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

Eu consegui fazer isso adicionando um parâmetro view bag no asp.net mvc. Aqui o que eu fiz

Adicionado ViewBag.Current = "Scheduler";como parâmetro em cada página

Página de layout

<ul class="nav navbar-nav">
     <li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action("Index","Scheduler")" target="_self">Scheduler</a></li>
 </ul>

Isso resolveu meu problema.

Damith
fonte
Solução simples e fácil.
japes Sophey 18/12/19
13

Pode ser um pouco tarde. Mas espero que isso ajude.

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

E uso como segue:

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

Obteve referência em http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html

Virag Dilip Desai
fonte
1
Solução muito simples e elegante. Fiz algumas melhorias aqui gist.github.com/jean-rakotozafy/… para destacar um menu para todas as ações do controlador.
Zan RAKOTO 27/02
5

Sei que essa pergunta é antiga, mas gostaria de adicionar minha voz aqui. Acredito que é uma boa idéia deixar o conhecimento de se um link está ou não ativo para o controlador da exibição.

Eu apenas definiria um valor exclusivo para cada visualização na ação do controlador. Por exemplo, se eu quisesse ativar o link da página inicial, faria algo assim:

public ActionResult Index()
{            
    ViewBag.Title = "Home";
    ViewBag.Home = "class = active";
    return View();
}

Então, na minha opinião, vou escrever algo assim:

<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>

Quando você navega para uma página diferente, diga Programas, o ViewBag.Home não existe (em vez disso, o ViewBag.Programs existe); portanto, nada é renderizado, nem mesmo class = "". Eu acho que isso é mais limpo, tanto para manutenção quanto para limpeza. Costumo sempre querer deixar a lógica fora da vista o máximo que posso.

mapussah
fonte
4

Considerando o que Damith postou, gosto de pensar que você pode se qualificar ativo pelo Viewbag.Title (a melhor prática é preencher isso nas suas páginas de conteúdo, permitindo que sua _Layout.cshtmlpágina mantenha suas barras de links). Observe também que se você estiver usando itens de submenu , também funcionará bem:

<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
fonte
Limpo e eficiente!
mggluscevic
3

I modificada do dom resposta "não é bonito" e tornou mais feia. Às vezes, dois controladores têm os nomes de ações conflitantes (ou seja, Índice), então eu faço isso:

<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>
DesenvolvedorDan
fonte
3

Você pode tentar o seguinte: No meu caso, estou carregando o menu do banco de dados com base no acesso baseado em funções, escreva o código em todas as visualizações no menu em que deseja ativar com base na visualização.

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

Esta solução é simples para o Asp.net MCV 5.

  1. Crie uma classe estática, por exemplo Utilitarios.cs.

  2. Dentro da classe, crie um 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. ligue assim

    <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>
Javier Deyvi Garcia, Saavedra
fonte
3

ASP.NET Core e Bootstrap 4

Resposta mais atualizada

Eu refiz a solução elegante do @crush para obter uma maneira atualizada, compatível com o ASP.NET Core e o Bootstrap 4 , para resolver esse problema com base em um IHtmlHelpermétodo de extensão:

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
fonte
1
Solução muito boa. No seu exemplo, como posso definir 'Contato' como ativo por padrão?
Dr. Suman Kabir 13/01
1
Obrigado. O bom é que você não precisa definir um elemento ativo. Assim que a página 'Contacto' é visitado, ActiveActionLink()será aplicada a classe ativa para a <li>:-)
WoIIe
onde você está verificando a área?
Mohammad
@ Mohamed eu não entendo. Você poderia elaborar sua pergunta?
WoIIe
na classe LinkExtensions você não obteve área de routeData!
Mohammad
3

Fácil ASP.NET Core 3.0 e 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");
            }
        }
    }
}

Inclua no seu _ViewImports.cs:

@addTagHelper *, YourAssemblyName

Uso:

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

Adicione '.ToString' para melhorar a comparação no 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>

-


fonte
Isso não funcionará se houver os mesmos nomes de ação em dois controladores diferentes. Teste-a com os controles Início e Sobre com a ação Índice.
Hyde
u poderia defind servidor de funções em navalha 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); } }e uso: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung
2

Também podemos criar a UrlHelperpartir do RequestContext, que podemos obter do próprio MvcHandler. Portanto, acredito que alguém que queira manter essa lógica nos modelos do Razor da seguinte maneira seria útil:

  1. Na raiz do projeto crie uma pasta chamada AppCode.
  2. Crie um arquivo lá chamado HtmlHelpers.cshtml
  3. Crie um ajudante lá:

    @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. Então podemos usar nossos pontos de vista como este:

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

Espero que ajude alguém.

Oleksii Aza
fonte
Isso é muito legal. Há alguma desvantagem de desempenho aqui?
esmagar
@crush, eu não o medi, mas esperaria que tivesse um baixo impacto no desempenho, porque acho que o framework usa uma lógica semelhante para criar a UrlHelperque você possui Controller.Url. A única coisa é que provavelmente não queremos executar a criação UrlHelperpara cada chamada, MenuItemportanto, podemos aplicar uma marcação para salvá-la nos itens HttpContext após a primeira chamada ao auxiliar, para fazer isso apenas uma vez por solicitação.
Oleksii Aza
2

é possível com uma função lambda

@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
    Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}

então uso

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

Criei uma HtmlHelperextensão que adiciona um ActiveActionLinkmétodo para aqueles que desejam adicionar a classe "ativa" ao próprio link, em vez de <li>envolvê-lo.


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

O uso é o seguinte:

@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })
A paixão súbita
fonte
1

a resposta por @dombenoit funciona. Embora ele introduz algum código para manter. Confira esta sintaxe:

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 o uso do .SetLinksActiveByControllerAndAction()método

Se você se pergunta o que torna essa sintaxe possível, confira o TwitterBootstrapMVC

Dmitry Efimenko
fonte
Obrigado pela resposta Dmitry, estou testando o TwitterBootstrapMVC
Gillespie
1

Eu também estava procurando uma solução e o jQuery ajudou bastante. Primeiro, você precisa dar 'id's aos seus <li>elementos.

<li id="listguides"><a href='/Guides/List'>List Guides</a></li>

Depois de fazer isso na sua página de layout, você pode dizer ao jQuery qual <li>elemento deve ser 'selecionado' na sua exibição.

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

Nota: Você precisa ter @RenderSection("scripts", required: false)em sua página de layout, um pouco antes da </body>tag para adicionar essa seção.

Doğa Gençer
fonte
1

Gostaria de propor esta solução que se baseia na primeira parte da resposta de Dom.

Primeiro, definimos duas variáveis, "ação" e "controlador" e as usamos para determinar o link ativo:

{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}

E depois:

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

Agora parece mais agradável e não há necessidade de soluções mais complexas.

Osama
fonte
0

se não estiver sendo exibido, o motivo é que você precisa de dois sinais @:

@@class

MAS, acredito que talvez você precise ter a classe ativa na marca "li" e não na marca "a". de acordo com os documentos de inicialização ( 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>

portanto, seu 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
fonte
A classe @@ gera um erro; originalmente eu tinha o seu exemplo de código acima, o que funciona, mas não é exatamente como o Actionlinks "deveria" ser?
precisa
editado. o @@ não é necessário. você tem que colocar a classe no EA
JC Lizard
0

Espero que isso ajude, abaixo está como seu menu pode ser:

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

E adicione a função auxiliar MVC abaixo da tag 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;
        }
    }

Consultei a resposta em http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/

Ganesh Todkar
fonte
0

Percebi que esse problema era um problema comum para alguns de nós, então publiquei minha própria solução usando o pacote nuget. Abaixo você pode ver como funciona. Espero que seja útil.

Nota: Este pacote de pepitas é o meu primeiro pacote. Portanto, se você encontrar um erro, envie um feedback. Obrigado.

  1. Instale o pacote ou faça o download do código-fonte e adicione seu projeto

    -Install-Package Betalgo.MvcMenuNavigator
  2. Adicione suas páginas a uma enumeração

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Coloque o filtro no topo do seu controlador ou ação

    [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. E use-o no layout do cabeçalho 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>

Mais informações: https://github.com/betalgo/MvcMenuNavigator

Tolga Kayhan
fonte
0

Eu acredito que aqui está um código mais limpo e menor para obter o menu selecionado sendo "ativo":

 <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
fonte
Bom, embora provavelmente deve ser estendida para o controlador e área em alguns casos
planetClaire
-1

Eu fiz a combinação das respostas acima e fiz a minha solução.

Assim..

Primeiro no bloco de barbear, crie uma variável de string que conterá o valor do nome do controlador e a ação que é chamada pelo usuário.

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

Em seguida, use a combinação de código HTML e 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>

Eu acho que isso é bom porque você não precisa acessar "ViewContext.RouteData.Values" toda vez para obter o nome do controlador e o nome da ação.

Nihad Delic
fonte
-1

Minha solução para este problema é

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

Uma maneira melhor pode ser adicionar um método de extensão Html para retornar o caminho atual a ser comparado com o link

Mudasar Rauf
fonte
-1

Eu fiz isso:

Ajudou na exibição parcial do menu

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

Em seguida, usei-o na tag anchor assim:

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

Meu aplicativo não tinha áreas, mas também pode ser incluído como outra variável na função auxiliar. E eu tive que passar a classe ativa para a marca âncora na minha opinião. Mas litambém pode ser configurado assim.

Anup Sharma
fonte
1
Você vê, voto negativo realmente não ajuda se você não mencionar o motivo.
Anup Sharma