Highlight Current Link

Posted on

Problem

I’m using this technique for highlighting current links (e.g. how the “Questions” link is highlighted on this very page you’re looking at). I changed the code a little bit and came up with this extension method:

    public static MvcHtmlString MenuLink(
        this HtmlHelper helper,
        string content, string action, string controller)
    {
        var routeData = helper.ViewContext.RouteData.Values;
        var currentController = routeData["controller"];
        var currentAction = routeData["action"];

        var builder = new TagBuilder("li")
        {
            InnerHtml = content
        };
        if (String.Equals(action, currentAction as string,
                  StringComparison.OrdinalIgnoreCase)
            &&
           String.Equals(controller, currentController as string,
                   StringComparison.OrdinalIgnoreCase))
        {
            builder.AddCssClass("active");
            return MvcHtmlString.Create(builder.ToString());
        }
        return MvcHtmlString.Create(builder.ToString());
    }

It works fine, But that’s some ugly code. I use the extension method this way:

@Html.MenuLink("<a href=" + @Url.Action("MainPage", "Ticket") + "><i class='fa  fa-fw fa-home'></i>Ticket Page</a>", "MainPage", "Ticket")

As you can see, part of that isn’t strongly typed.

Do you have any ideas to improve the extension method?

Solution

One thing that I see that I would change is the if statement

    if (String.Equals(action, currentAction as string,
              StringComparison.OrdinalIgnoreCase)
        &&
       String.Equals(controller, currentController as string,
               StringComparison.OrdinalIgnoreCase))
    {
        builder.AddCssClass("active");
        return MvcHtmlString.Create(builder.ToString());
    }

I personally don’t like having a conditional that spans over multiple lines, so the first thing that I would do is to take the boolean conditions and make them into boolean variables and then use them inside the conditional. I think it would be easier to read.

bool isCurrentAction = String.Equals(action, currentAction as string,
          StringComparison.OrdinalIgnoreCase);
bool isCurrentController = String.Equals(controller, currentController as string,
           StringComparison.OrdinalIgnoreCase);
if (isCurrentAction && isCurrentController)
{
    builder.AddCssClass("active");
    return MvcHtmlString.Create(builder.ToString());
}

And since you are returning builder immediately after the if statement, there isn’t really a reason to return inside the if statement, it is rather redundant. Just delete that from the if block

bool isCurrentAction = String.Equals(action, currentAction as string,
          StringComparison.OrdinalIgnoreCase);
bool isCurrentController = String.Equals(controller, currentController as string,
           StringComparison.OrdinalIgnoreCase);
if (isCurrentAction && isCurrentController)
{
    builder.AddCssClass("active");
}

Leave a Reply

Your email address will not be published. Required fields are marked *