grimboite/articles/dev/2015-01-13-active-link.md

3.8 KiB

Title Date Slug Tags
Lien actif dans une page 2015-01-13 active-link-in-a-page web, code, dev, dotnet, html

Un élément essentiel pour la compréhension de l'interface utilisateur est de savoir où on se trouve. Pour cela, il existe plusieurs patterns (breadcrumb, historique de navigation, ...): tout pour éviter que l'utilisateur n'appuye quatorze fois sur la touche retour en espérant tomber sur la bonne page.

Un élément à combiner avec les idées ci-dessous est de placer le lien actif de la page en gras, afin d'avoir une bonne visualisation de "où suis-je?".

On commence par créer un helper, qui permet de générer dynamiquement un élément <li> auquel est associé la classe CSS active s'il correspond à l'URL actuelle du navigateur.

using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace RPS.Web.Helpers
{
    public static class MenuExtensions
    {
        public static MvcHtmlString MenuItem(
            this HtmlHelper htmlHelper,
            string text,
            string action,
            string controller,
            object routeValues,
            object htmlAttributes
        )
        {
            var li = new TagBuilder("li"); 										// ajoute l'élément <li></li>
            var routeData = htmlHelper.ViewContext.RouteData; 					// récupère la route
            var currentAction = routeData.GetRequiredString("action"); 			// récupère l'action
            var currentController = routeData.GetRequiredString("controller"); 	// récupère le contrôleur
            if (String.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
                String.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
            {
                li.AddCssClass("active"); // si l'url correspond à la route, on ajoute une classe `active` sur l'élément `<li>`.
            }

			// construit le code HTML à l'intérieur de la balise <li> avec un `ActionLink`
            li.InnerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, htmlAttributes).ToHtmlString();

            return MvcHtmlString.Create(li.ToString());
        }
    }
}

Dernier problème: cette extension de méthode ne peut être appelée directement depuis la syntaxe Razor. Pour pallier à cela, il suffit d'ajouter le namespace défini ci-dessus dans le fichier Web.config qui se trouve dans le répertoire Views:

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="RPS.Web.Helpers" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

On peut ensuite l'appeler directement dans le rendu HTML de la page (pas besoin de définir l'élément li, puisque celui-ci sera généré par le helper):

<ul id="entityLinksMenu">
	@Html.MenuItem("Details", "Details", "Entity", new { id = Model.ID }, null)
	@Html.MenuItem("Display", "Display", "Entity", new { id = Model.ID }, null)
</ul>

Finalement, on ajoute une classe .active dans le style CSS:

#entityLinksMenu li.active {
	font-weight: bold;
}

Références