Geeks With Blogs
bobby's blog randomly specific...

Have you ever needed to detect what part of the application is currently being viewed?  This might be a bigger issue if you write a lot of shared/partial views or custom display or editor templates.  Another scenario, which is the one I encountered when I first started down this path, is when you have some type of menu and you’d like to be able to determine which item represents the current page so you can highlight it in some way.  A simple example is the menu that is created as part of the default ASP.NET MVC 2 Application template.

 

<div id="menucontainer">

 

    <ul id="menu">

        <li><%= Html.ActionLink("Home", "Index", "Home") %></li>

        <li><%= Html.ActionLink("About", "About", "Home") %></li>

    </ul>

 

</div>

 

The part that got me at first, however, was the following entry in the default style sheet (Site.css):

 

ul#menu li.selected a

{

    background-color: #fff;

    color: #000;

}

 

I assumed that the .selected class would automatically get applied to the active menu item.  After trying a few different things, including the MvcContrib MenuBuilder, I decided to write my own extension methods so I would have more control over the output.  First, I needed a way to determine what view the user has navigated to based on the requested URL and route configuration.  Now, I am sure there are many ways to do this, but this is what I came up with:

 

public static class RequestExtensions

{

    public static bool IsCurrentRoute(this RequestContext context, String areaName,

        String controllerName, params String[] actionNames)

    {

        var routeData = context.RouteData;

        var routeArea = routeData.DataTokens["area"] as String;

        var current = false;

 

        if ( ((String.IsNullOrEmpty(routeArea) && String.IsNullOrEmpty(areaName)) ||

              (routeArea == areaName)) &&

             ((String.IsNullOrEmpty(controllerName)) ||

              (routeData.GetRequiredString("controller") == controllerName)) &&

             ((actionNames == null) ||

               actionNames.Contains(routeData.GetRequiredString("action"))) )

        {

            current = true;

        }

 

        return current;

    }

 

    // additional overloads omitted...

}

 

With that in place, I was able to write several UrlHelper methods that check if the supplied values map to the current view.

 

public static class UrlExtensions

{

    public static bool IsCurrent(this UrlHelper urlHelper, String areaName,

        String controllerName, params String[] actionNames)

    {

        return urlHelper.RequestContext.IsCurrentRoute(areaName, controllerName, actionNames);

    }

 

    public static string Selected(this UrlHelper urlHelper, String areaName,

        String controllerName, params String[] actionNames)

    {

        return urlHelper.IsCurrent(areaName, controllerName, actionNames)

            ? "selected" : String.Empty;

    }

 

    // additional overloads omitted...

}

 

Now I can re-work the original menu to utilize these new methods.  Note: be sure to import the proper namespace so the extension methods become available inside your views!

 

<div id="menucontainer">

 

    <ul id="menu">

        <li class="<%= Url.Selected(null, "Home", "Index") %>">

            <%= Html.ActionLink("Home", "Index", "Home")%></li>

 

        <li class="<%= Url.Selected(null, "Home", "About") %>">

            <%= Html.ActionLink("About", "About", "Home")%></li>

    </ul>

 

</div>

 

If we take it one step further, we can clean up the markup even more.  Check out the Html.ActionMenuItem() extension method and the refined menu:

 

public static class HtmlExtensions

{

    public static MvcHtmlString ActionMenuItem(this HtmlHelper htmlHelper, String linkText,

        String actionName, String controllerName)

    {

        var html = new StringBuilder("<li");

 

        if ( htmlHelper.ViewContext.RequestContext

                .IsCurrentRoute(null, controllerName, actionName) )

        {

            html.Append(" class=\"selected\"");

        }

 

        html.Append(">")

            .Append(htmlHelper.ActionLink(linkText, actionName, controllerName))

            .Append("</li>");

 

        return MvcHtmlString.Create(html.ToString());

    }

 

    // additional overloads omitted...

}

 

UPDATE: Thanks to Ryan for reminding me to use the TagBuilder class instead of the StringBuilder for generating the HTML for the menu item!  Here is the refactored method:

 

public static class HtmlExtensions

{

    public static MvcHtmlString ActionMenuItem(this HtmlHelper htmlHelper, String linkText,

        String actionName, String controllerName)

    {

        var tag = new TagBuilder("li");

 

        if ( htmlHelper.ViewContext.RequestContext

            .IsCurrentRoute(null, controllerName, actionName) )

        {

            tag.AddCssClass("selected");

        }

 

        tag.InnerHtml = htmlHelper.ActionLink(linkText, actionName, controllerName).ToString();

 

        return MvcHtmlString.Create(tag.ToString());

    }

}

 

<div id="menucontainer">

 

    <ul id="menu">

        <%= Html.ActionMenuItem("Home", "Index", "Home") %>

        <%= Html.ActionMenuItem("About", "About", "Home") %>

    </ul>

 

</div>

 

Which generates the following HTML:

 

<div id="menucontainer">

 

    <ul id="menu">

        <li class="selected"><a href="/">Home</a></li>

        <li><a href="/Home/About">About</a></li>

    </ul>

 

</div>

 

I have created a codepaste of these extension methods if you are interested in using them in your own projects.  Enjoy!

Posted on Friday, April 9, 2010 12:13 AM ASP.NET , MVC | Back to top


Comments on this post: Handy ASP.NET MVC 2 Extension Methods – Where am I?

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
You might want to take a look at TagBuilder to get rid of that string builder.

http://www.asp.net/learn/mvc/tutorial-35-cs.aspx
Left by Ryan on Apr 10, 2010 8:31 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Thanks Ryan! I have updated the post with the refactored method.
Left by Bobby Diaz on Apr 11, 2010 10:37 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Thanks, exactly what I was looking for
Left by Jarod Ferguson on May 25, 2010 2:37 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Good post, I can’t say that I agree with everything that was said, but very good information overall:) http://www.clothingseries.com wholesale gucci mens slim jeans is so cute!
Left by Welcome on Jun 11, 2010 3:16 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Thank you for this great post, it's a quite simple way to do this. I couldn't get it to work at first, but then i read 'import the proper namespace' :-)
Left by Koen Stroobants on Aug 28, 2010 10:24 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Great example! This is exactly what I was looking for to solve this issue. Thanks.
Left by Robert on Sep 02, 2010 10:28 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Great post, just what I was looking for. Thanks for the help!
Left by Mani Gandham on Sep 07, 2010 7:24 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
great post... i needed that for my projects
thank you
Left by Alexandre Jobin on Sep 13, 2010 12:37 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Can someone tell me the routing namespace that contains the IsCurrentRoute method
Left by Jon on Sep 24, 2010 12:33 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Sorry didn't read it properly. Long day.
Left by Jon on Sep 24, 2010 12:44 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Great post. Just what I was looking for.
Left by Lars Olav on Sep 28, 2010 4:06 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
The blog are the main media of knowing about the world that what is going on in this world and what is gonna be. this is one of the best that kind of blog which has lot of those information which everyone like to have. I personally like to thank to this blog.
Left by opdrachten on Feb 06, 2011 3:36 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Congratulations for your code !
however, one bug (or not ? ).
it works when Im on the "index" view, but when Im passing on the "edit" view, its not "selected" anymore.
Is it normal ?
Left by Peterslast on Mar 30, 2011 2:56 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Great post. I have extended the functionality of your extension to highlight menu items when another controller and action is used.

http://arturito.net/2011/08/03/asp-net-mvc-2-highlight-selected-menu-item-on-the-site-master-without-session/
Left by Arturito on Aug 03, 2011 1:11 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
As a new MVC developer I must say thank you! This is exactly what I was looking for.
Left by John Phillips on Oct 20, 2011 10:06 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
One thing to mention about the IsCurrent function, when you don't pass any parameters you'll get an empty string[]. In your function you do a actionNames == null check this will only be true if you pass a null into the params parameter. You could do a check for actionNames.Any()

((actionNames == null) || !actionNames.Any() || actionNames.Contains(routeData.GetRequiredString("action")))

Left by Wouter Boevink on Oct 21, 2011 6:00 AM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Just great.

I have to change it a little because I'm using in RenderAction so it's being called in different RequestContext (special Action and Controller for menu).
Left by Michal on Sep 18, 2013 2:47 PM

# re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Requesting Gravatar...
Hi Bobby,

This is great, exactly what I was looking for.
I noticed however, when using this as part of Areas, the IsCurrent is always returning false, as areaName is being passed as null...

If outside of the Areas, it is working fine though.
Left by RickD on Oct 09, 2013 7:47 AM

Your comment:
 (will show your gravatar)


Copyright © Bobby Diaz | Powered by: GeeksWithBlogs.net