bobby's blog

randomly specific...


News

My Stats

  • Posts - 15
  • Comments - 48
  • Trackbacks - 0

Twitter












Recent Comments


Recent Posts


Archives


Post Categories


Image Galleries


My Links


User Groups



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!

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Comments

Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Ryan on 4/10/2010 8:31 PM
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
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Bobby Diaz on 4/11/2010 10:37 AM
Thanks Ryan! I have updated the post with the refactored method.
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Jarod Ferguson on 5/25/2010 2:37 PM
Thanks, exactly what I was looking for
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Welcome on 6/11/2010 3:16 AM
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!
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Koen Stroobants on 8/28/2010 10:24 AM
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' :-)
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Robert on 9/2/2010 10:28 PM
Great example! This is exactly what I was looking for to solve this issue. Thanks.
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Mani Gandham on 9/7/2010 7:24 PM
Great post, just what I was looking for. Thanks for the help!
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Alexandre Jobin on 9/13/2010 12:37 PM
great post... i needed that for my projects
thank you
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Jon on 9/24/2010 12:33 PM
Can someone tell me the routing namespace that contains the IsCurrentRoute method
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Jon on 9/24/2010 12:44 PM
Sorry didn't read it properly. Long day.
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Lars Olav on 9/28/2010 4:06 AM
Great post. Just what I was looking for.
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by opdrachten on 2/6/2011 3:36 AM
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.
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Peterslast on 3/30/2011 2:56 AM
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 ?
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Arturito on 8/3/2011 1:11 PM
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/
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by John Phillips on 10/20/2011 10:06 PM
As a new MVC developer I must say thank you! This is exactly what I was looking for.
Gravatar # re: Handy ASP.NET MVC 2 Extension Methods – Where am I?
Posted by Wouter Boevink on 10/21/2011 6:00 AM
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")))


Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: