Friday, January 14, 2011

Highlighting Active menu item the ASP.NET MVC way

As you deduced from the title we will investigate different options we have to highlight menu items in the view based on our user's current navigation in the web application.


  • A single menu items usually ends up representing multiple views
  • I assume you are using ASP.NET MVC areas to logically group views in the application together 
  • and you want to highlight/select the menu item that represents the current section/area that your user is working on
  • You implemented a menu system on the master page(lay out page as MVC 3 nerds wish to name it) as it is shared by all views of the application.
To meet the above requirement we need to device a mechanism to:
  1. Keep track of the  current section/area of the application that our user is using. 
  2. High light the menu item
  3. and finnally pass the current section to the view 
Lets us dig into the solution using a simple example, for the menu system displayed below, we want Posting menu item to get highlighted for any view in the posting area/section and like wise for the rest of the areas. 

I created the TopMenu enum to represent the menu items:

and this HtmlHelper extension for reasons that become apparent as you read on :

and finally the portion of the view in the master page that contains the menu items : 

For those of you who got lost, the ActiveMenu HtmlHelper extension returns either nothing or something like class="active" and web designers know how to associate a style to the css class.Taking it from here our next concern is how we are going to determine and pass the proper TopMenu object as a ViewData entry.

The first dirty option

 Obviously this is not a good option, not maintainable and not clean!

The Second option
The second option is to use ASP.NET MVC ActionFilter to keep the logic DRY.

The idea is simple the filter encapsulates the logic to determine the active menu and add the correct TopMenu object to ViewData, neat right? But we still need to apply [MenuFilter] to controller actions or on every controller or better yet on a base controller if you have one.

The Third option

This is my preferred method: The only difference with option 2 is how I am going to apply the Filter to my actions: Here is where global filter comes in handy. I don't want to discuss global filters on this post because that is not my intention(DRY ... aha), refer Brad Wilson's blog about the subject.

Here is the filter provider:

Once we have the filter provider registering our MenuFilter globally is very simple, include the following code snippet in the Global.asax.cs:
Take it easy, the first line is not part of menu system, as depicted above it only takes three lines to register your filter globally. You probably need the Filter for HTTP GET requests that is why we have the lambda expression on the third line.

 I appreciate your time, Thanks.


1 comment:

  1. I have been trying to get this working as well and I came up with this:
    ....which I think is a quite clean solution.