Comment ajouter une classe «active» à Html.ActionLink dans ASP.NET MVC


128

J'essaie d'ajouter une classe "active" à ma barre de navigation bootstrap dans MVC, mais ce qui suit ne montre pas la classe active lorsqu'elle est écrite comme ceci:

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

Cela résout ce qui ressemble à une classe correctement formatée, mais ne fonctionne pas:

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

Dans la documentation Bootstrap, il est indiqué que les balises «a» ne doivent pas être utilisées dans la barre de navigation, mais ce qui précède est à mon avis la manière correcte d'ajouter une classe à un Html.ActionLink. Y a-t-il une autre façon (ordonnée) de faire cela?


3
le code qui résout contient class = active. N'est-ce pas ce que vous dites vouloir dans votre question? Comment vous avez votre code, c'est comment j'ajoute des cours
Matt Bodily

tu n'es pas trop clair !!! Je ne comprends pas exactement quel est le problème de l'ajouter à la navigation, même si j'ai un sentiment, la façon dont il est devrait être très bien
JC Lizard

1
Quel est le problème avec le code résolu? Qu'attendez-vous? Pouvez-vous être plus précis que «ne semble pas fonctionner»? Votre question n'est pas assez claire pour vous aider pour le moment.
dom

Édité! désolé, ce que je voulais dire, c'est que la classe "active" ne s'affiche pas du tout
Gillespie

2
Je viens de jeter un coup d'œil aux documents de Bootstrap et je pense que vous devez ajouter la activeclasse à l' liélément, pas le a. Voir le premier exemple ici: getbootstrap.com/components/#navbar
dom

Réponses:


300

Dans Bootstrap, la activeclasse doit être appliquée à l' <li>élément et non au <a>. Voir le premier exemple ici: http://getbootstrap.com/components/#navbar

La façon dont vous gérez votre style d'interface utilisateur en fonction de ce qui est actif ou non n'a rien à voir avec l' ActionLinkaide d' ASP.NET MVC . C'est la solution appropriée pour suivre la manière dont le framework Bootstrap a été construit.

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

Éditer:

Étant donné que vous réutiliserez probablement votre menu sur plusieurs pages, il serait judicieux de disposer d'un moyen d'appliquer automatiquement cette classe sélectionnée en fonction de la page actuelle plutôt que de copier le menu plusieurs fois et de le faire manuellement.

Le moyen le plus simple consiste simplement à utiliser les valeurs contenues dans ViewContext.RouteData, à savoir les valeurs Actionet Controller. Nous pourrions construire sur ce que vous avez actuellement avec quelque chose comme ceci:

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

Ce n'est pas joli dans le code, mais cela fera le travail et vous permettra d'extraire votre menu dans une vue partielle si vous le souhaitez. Il existe des moyens de le faire d'une manière beaucoup plus propre, mais puisque vous ne faites que commencer, je vais en rester là. Bonne chance pour apprendre ASP.NET MVC!


Modification tardive:

Cette question semble générer un peu de trafic, alors j'ai pensé que je proposerais une solution plus élégante en utilisant une HtmlHelperextension.

Edit 03-24-2015: J'ai dû réécrire cette méthode pour permettre plusieurs actions et contrôleurs déclenchant le comportement sélectionné, ainsi que la gestion du moment où la méthode est appelée à partir d'une vue partielle d'action enfant, j'ai pensé partager la mise à jour!

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

Fonctionne avec .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;
}

Exemple d'utilisation:

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

Merci, comme je l'ai mentionné, c'est comme ça que je l'ai eu à l'origine, mais j'espérais avoir une méthode dans tout mon code pour changer la classe "active" entre les objets sélectionnés.
Gillespie

2
@Gillespie pas de soucis! J'ai modifié ma réponse pour ajouter des informations qui pourraient vous aider un peu plus.
dom

5
En ce qui concerne la première modification, cela n'a fonctionné que pour la page d'index. Il semble que la raison en est que lors de la comparaison, il a échoué car ViewContext.RouteData.Values ​​["Action"] ne renvoie pas d'objet de type String (je ne sais toujours pas comment cela fonctionnait pour la première page ....) . Quand j'ai changé tous ViewContext.RouteData.Values ​​["Action"] en ViewContext.RouteData.Values ​​["Action"]. ToString (), cela fonctionnait pour toutes les pages. Vous voudrez peut-être l'ajouter à votre solution au cas où quelqu'un rencontrerait le même problème.
user3281466

2
@LonelyPixel peut - être que cette réponse fonctionne pour vous?
dom

1
Pour les utilisateurs de VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Accueil "," Index "," Accueil ") </li>
Andrea Antonangeli

28

Extension:

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

Usage:

<ul class="nav navbar-nav">
    @Html.LiActionLink("About", "About", "Home")
    @Html.LiActionLink("Contact", "Contact", "Home")
</ul>

1
C'est une extension magnifiquement efficace. Fonctionne parfaitement et est assez élégant. Chapeau à vous, Prof! Mon seul reproche concerne le role="presentation", ce qui n'est pas du tout approprié pour un menu de navigation principal ( john.foliot.ca/aria-hidden/#pr ). Une liste non ordonnée est tout à fait un conteneur approprié pour un ensemble de liens connexes, car elle les regroupe de manière logique.
René Kåbis

@ René Kåbis it for bootstrap naigation getbootstrap.com/components/#nav-tabs
Prof

1
Cela ne fonctionne pas lorsque l'utilisateur saisit manuellement l'URL en minuscule ou en majuscule, par exemple. " domain.com/Login " et " domain.com/LOGIN ". Pour la solution, 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

J'ai réussi à le faire en ajoutant un paramètre de sac de vue dans asp.net mvc. Ici qu'est-ce que j'ai fait

Ajout d' ViewBag.Current = "Scheduler";un paramètre similaire dans chaque page

Dans la page de mise en page

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

Cela a résolu mon problème.


Solution simple et facile.
japes Sophey

13

Peut-être un peu tard. Mais j'espère que cela vous aidera.

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

Et l'utilisation comme suit:

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

Obtenu une référence de http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html


1
Solution très simple et élégante. J'ai fait quelques améliorations ici gist.github.com/jean-rakotozafy/ ... pour mettre en évidence un menu pour toutes les actions du contrôleur.
Zan RAKOTO

5

Je sais que cette question est ancienne, mais j'aimerais simplement ajouter ma voix ici. Je pense que c'est une bonne idée de laisser au contrôleur de la vue le fait de savoir si un lien est actif ou non.

Je définirais simplement une valeur unique pour chaque vue dans l'action du contrôleur. Par exemple, si je voulais activer le lien de la page d'accueil, je ferais quelque chose comme ceci:

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

Ensuite, à mon avis, j'écrirai quelque chose comme ceci:

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

Lorsque vous accédez à une autre page, disons Programmes, ViewBag.Home n'existe pas (c'est le cas de ViewBag.Programs); par conséquent, rien n'est rendu, pas même class = "". Je pense que c'est plus propre à la fois pour la maintenabilité et la propreté. J'ai tendance à toujours vouloir laisser la logique hors de vue autant que possible.


4

Compte tenu de ce que Damith a publié, j'aime penser que vous pouvez simplement vous qualifier actif par le Viewbag.Title (la meilleure pratique consiste à renseigner cela dans vos pages de contenu en permettant à votre _Layout.cshtmlpage de contenir vos barres de liens). Notez également que si vous utilisez des éléments de sous-menu, cela fonctionne également très 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>

Propre et efficace!
mggluscevic

3

J'ai modifié la réponse «pas jolie» de dom et l' ai rendue plus moche. Parfois, deux contrôleurs ont les noms d'action en conflit (c'est-à-dire Index), alors je fais ceci:

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

3

Vous pouvez essayer ceci: Dans mon cas, je charge le menu à partir de la base de données en fonction de l'accès basé sur les rôles, écrivez le code sur chaque vue quel menu vous souhaitez activer en fonction de votre vue.

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

3

Cette solution est simple pour Asp.net MCV 5.

  1. Créez une classe statique, par exemple Utilitarios.cs.

  2. À l'intérieur de la classe, créez une méthode statique:

    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. appelle comme ça

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

3

ASP.NET Core et Bootstrap 4

Réponse la plus à jour

J'ai retravaillé la solution soignée de @crush pour un moyen mis à jour, compatible ASP.NET Core et Bootstrap 4 pour résoudre ce problème basé sur une IHtmlHelperméthode d'extension:

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

Usage

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

1
Très bonne solution. Dans votre exemple, comment puis-je définir «Contact» comme actif par défaut?
Md. Suman Kabir le

1
Je vous remercie. La bonne chose est que vous n'avez pas besoin de définir un élément actif. Dès que la page 'Contact' est visitée, ActiveActionLink()appliquera la classe active à la <li>:-)
WoIIe

où est votre zone de contrôle?
Mohammad le

@Mohammad je ne comprends pas. Pouvez-vous préciser votre question?
WoIIe

dans la classe LinkExtensions, vous n'avez pas obtenu de zone de routeData!
Mohammad le

3

Easy ASP.NET Core 3.0 et 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");
            }
        }
    }
}

Incluez dans votre _ViewImports.cs:

@addTagHelper *, YourAssemblyName

Usage:

 <li active-when="/Home/Index">

2

Ajouter '.ToString' pour améliorer la comparaison sur 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>

-


Cela ne fonctionnera pas s'il y a les mêmes noms d'action dans deux contrôleurs différents. Testez-le avec les contrôleurs Accueil et À propos avec l'action Index.
hyde

Vous pouvez définir le serveur de fonction sur le rasoir comme: @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); } }et l'utilisation: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung

2

Nous pouvons également créer à UrlHelperpartir de RequestContext que nous pouvons obtenir à partir de MvcHandler lui-même. Par conséquent, je pense que pour quelqu'un qui souhaite conserver cette logique dans les modèles Razor, la manière suivante serait utile:

  1. Dans la racine du projet, créez un dossier nommé AppCode.
  2. Créez un fichier nommé HtmlHelpers.cshtml
  3. Créez un assistant là-dedans:

    @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. Ensuite, nous pouvons utiliser nos vues comme ceci:

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

J'espère que cela aide quelqu'un.


C'est vraiment cool. Y a-t-il des inconvénients de performances ici?
écraser le

@crush, je ne l'ai pas mesuré, mais je m'attendrais à ce qu'il ait un faible impact sur les performances car je pense que le cadre utilise une logique similaire pour créer UrlHelpercelle que vous avez Controller.Url. La seule chose est que nous ne voulons probablement pas exécuter la création UrlHelperpour chaque appel à MenuItemafin que nous puissions appliquer une coche pour l'enregistrer dans HttpContext Items après le premier appel à l'assistant, donc nous ne le faisons qu'une fois par requête.
Oleksii Aza

2

est possible avec une fonction lambda

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

puis utilisation

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

2

J'ai créé une HtmlHelperextension qui ajoute une ActiveActionLinkméthode pour ceux d'entre vous qui veulent ajouter la classe "active" au lien lui-même plutôt que l' <li>entourant du lien.


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

L'utilisation est la suivante:

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

1

la réponse de @dombenoit fonctionne. Bien qu'il introduit du code à maintenir. Vérifiez cette syntaxe:

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", "#")
}

Remarquez l'utilisation de la .SetLinksActiveByControllerAndAction()méthode.

Si vous vous demandez ce qui rend cette syntaxe possible, consultez TwitterBootstrapMVC


Merci pour la réponse Dmitry, je teste TwitterBootstrapMVC
Gillespie

1

Je cherchais également une solution et jQuery m'a beaucoup aidé. Tout d'abord, vous devez donner des «identifiants» à vos <li>éléments.

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

Après avoir fait cela dans votre page de mise en page, vous pouvez indiquer à jQuery quel <li>élément doit être «sélectionné» dans votre vue.

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

Remarque: vous devez avoir @RenderSection("scripts", required: false)dans votre page de mise en page, juste avant la </body>balise pour ajouter cette section.


1

Je voudrais proposer cette solution qui est basée sur la première partie de la réponse de Dom.

Nous définissons d'abord deux variables, "action" et "controller" et les utilisons pour déterminer le lien actif:

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

Puis:

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

Maintenant, il semble plus joli et pas besoin de solutions plus complexes.


0

s'il ne s'affiche pas du tout, la raison en est que vous avez besoin de deux signes @:

@@class

MAIS, je pense que vous devrez peut-être avoir la classe active sur la balise "li" et non sur la balise "a". selon la documentation 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>

donc votre code sera:

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

La classe @@ génère une erreur, j'avais à l'origine votre exemple de code ci-dessus, qui fonctionne, mais n'est pas exactement comme Actionlinks "devrait" être?
Gillespie

édité. le @@ n'est pas obligatoire. vous devez mettre la classe sur l'EA
JC Lizard

0

J'espère que cela vous aidera, voici comment votre menu peut être:

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

Et ajoutez ci-dessous la fonction d'assistance MVC sous la balise 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;
        }
    }

J'ai renvoyé la réponse de http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/


0

J'ai réalisé que ce problème était un problème courant pour certains d'entre nous, j'ai donc publié ma propre solution en utilisant le package nuget. Ci-dessous, vous pouvez voir comment cela fonctionne. J'espère que cela sera utile.

Remarque: ce paquet nuget est mon premier paquet. Donc, si vous voyez une erreur, veuillez donner votre avis. Je vous remercie.

  1. Installez le package ou téléchargez le code source et ajoutez votre projet

    -Install-Package Betalgo.MvcMenuNavigator
  2. Ajoutez vos pages à une énumération

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Placez le filtre en haut de votre contrôleur ou action

    [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. Et utilisez-le dans votre mise en page d'en-tête comme ceci

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

Plus d'informations: https://github.com/betalgo/MvcMenuNavigator


0

Je crois que voici un code plus propre et plus petit pour faire en sorte que le menu sélectionné soit "actif":

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

Bien, bien qu'il
doive

-1

J'ai fait la combinaison des réponses ci-dessus et fait ma solution.

Alors..

Tout d'abord, dans le bloc rasoir, créez une variable de chaîne qui contiendra la valeur du nom du contrôleur et l'action appelée par l'utilisateur.

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

Ensuite, utilisez une combinaison de code HTML et 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>

Je pense que c'est bien parce que vous n'avez pas besoin d'accéder à "ViewContext.RouteData.Values" à chaque fois pour obtenir le nom du contrôleur et le nom de l'action.


-1

Ma solution à ce problème est

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

Un meilleur moyen peut être d'ajouter une méthode d'extension Html pour renvoyer le chemin actuel à comparer avec le lien


-1

J'ai fait ça:

Création d'un assistant dans la vue partielle du 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>}
}

Ensuite, utilisez-le dans la balise d'ancrage comme ceci:

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

Mon application n'avait pas de zones mais elle peut également être incluse comme une autre variable dans la fonction d'assistance. Et je devais passer la classe active à la balise d'ancrage à mon avis. Mais lipeut également être configuré comme ça.


1
Vous voyez, un vote défavorable n'aide pas vraiment si vous ne mentionnez pas la raison.
Anup Sharma
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.