tags:

views:

2120

answers:

7

In the default asp.net mvc project, in the Site.Master file, there is a menu navigation list:

<div id="menucontainer">
    <ul id="menu">              
        <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
        <li><%= Html.ActionLink("About Us", "About", "Home")%></li>
    </ul>
</div>

This renders in the browser to:

<div id="menucontainer"> 
    <ul id="menu">              
        <li><a href="/">Home</a></li> 
        <li><a href="/Home/About">About Us</a></li> 
    </ul> 
</div>

I want to be able to dynamically set the active list item, based on the view that is being called. That is, when the user is looking at the home page, I would want the following HTML to be created:

<div id="menucontainer"> 
    <ul id="menu">              
        <li class="active"><a href="/">Home</a></li> 
        <li><a href="/Home/About">About Us</a></li> 
    </ul> 
</div>

I would expect that the way to do this would be something like:

<div id="menucontainer">
    <ul id="menu">              
        <li <% if(actionName == "Index"){%> class="active"<%}%>><%= Html.ActionLink("Home", "Index", "Home")%></li>
        <li <% if(actionName == "About"){%> class="active"<%}%>><%= Html.ActionLink("About Us", "About", "Home")%></li>
    </ul>
</div>

The key bit here is the <% if(actionName == "Index"){%> class="active"<%}%> line. I do not know how to determine what the current actionName is.

Any suggestions on how to do this? Or, if I'm on completely the wrong track, is there a better way to do this?

A: 

The fact that your View has to know about your controller's actions is breaking with the MVC pattern. Perhaps your controller could pass some "control" information to the view to ultimately allow it to accomplish the same thing, the only difference is who is in charge.

Like in your controller's action you could:

public ActionResult Index(){
     ViewData["currentAction"] = "Index";
     //... other code
    return View();
}

Then over in your view you could:

<% if( ((string)ViewData["currentAction"]) == "Index" {%> <!- some links --><% } %>
<% if( ((string)ViewData["currentAction"]) == "SomethingElse" {%> <!- some links --><% } %>

However, the more I think about it the more I question why you are using the same View for multiple actions. Is the view that similar?

If the use case justifies it then go with my above suggestion. But otherwise perhaps you could break things out into multiple views (one for each controller action) and the problem solves itself.

Jason Whitehorn
A: 

Try

<% if(ViewContext.ViewName == "Index"){%>

Should work fine !!!

EDIT : REMOVED IN BETA1

Removed the ViewName property from the ViewContext class.

+5  A: 

Inside a view, you can get the current action name with:

ViewContext.RouteData.Values["action"].ToString()
Craig Stuntz
A: 

Based on the previous answers, here is what my current solution is for the same issue:

In the master page I give each li an id that corresponds to the controller and the action, since this should be known from the ActionLink. I was previously doing this with the page title but this helps with organization.

Site.Master:

<ul id="menu">
    <li id="menuHomeIndex" runat="server"><%= Html.ActionLink("Home", "Index", "Home") %></li>
    <li id="menuHomeAbout" runat="server"><%= Html.ActionLink("About Us", "About", "Home") %></li>
</ul>

Site.Master.cs:

// This is called in Page_Load
private void SetActiveLink()
{
    string action = "" + ViewContext.RouteData.Values["controller"] + ViewContext.RouteData.Values["action"];
    var activeMenu = (HtmlGenericControl)Page.Master.FindControl("menu" + action);

    if (activeMenu != null)
    {
        activeMenu.Attributes.Add("class", "selected");
    }
}

It's more work than the inline code but I think it's cleaner and also lets you have actions with the same name in different controllers. So if you add more menu items with different controllers, not all actions named Index will be highlighted in the menu.

If anyone sees issues with this approach please let me know.

Jonathan S.
+3  A: 

You can also try to detect which is the current selected tab from its controller name and view name, then add the class attribute.

     public static string MenuActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName)
 {
  var htmlAttributes = new RouteValueDictionary();

  if (helper.ViewContext.Controller.GetType().Name.Equals(controllerName + "Controller", StringComparison.OrdinalIgnoreCase))
  {
   htmlAttributes.Add("class", "current");
  }

  return helper.ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(), htmlAttributes);
 }
labilbe
A: 

This should work using jQuery on the client side of things, uses Google to serve the latest jQuery library:

<script src="http://www.google.com/jsapi" type="text/javascript" language="javascript"></script>
<script type="text/javascript" language="javascript">google.load("jquery", "1");</script>  

<script language="javascript" type="text/javascript">
      $(document).ready(function(){
          var str=location.href.toLowerCase(); 
        $('#menucontainer ul#menu li a').each(function() {
                if (str.indexOf(this.href.toLowerCase()) > -1) {
                        $(this).attr("class","current"); //hightlight parent tab
                     }  
                });
      });  
    </script>
Slee
+13  A: 

I made myself a helper method to handle this type of thing. In the code behind of my master page (could be pushed of to an extension method ... probably a better approach), I put the following code.

protected string ActiveActionLinkHelper(string linkText, string actionName, string controlName, string activeClassName)
{
    if (ViewContext.RouteData.Values["action"].ToString() == actionName && 
            ViewContext.RouteData.Values["controller"].ToString() == controlName)
        return Html.ActionLink(linkText, actionName, controlName, new { Class = "selected" });

    return Html.ActionLink(linkText, actionName, controlName);
}

Then, I just call it in my page like so.

<%= ActiveActionLinkHelper("Home", "Index", "Home", "selected")%>

Adam Carr