Reputation: 11296
I have the following menu in my masterpage:
<ul id="menu" class="lavaLampBottomStyle">
<li>
<%= Html.ActionLink("Employees", "Index", "Employees")%></li>
<li>
<%= Html.ActionLink("Customer", "Details", "Account")%></li>
</ul>
I need a way to set the css class of the current active li to "current".
My first guess it to do this with the assistance of javascript.
I would include something like this in the masterpage:
$("#menu li a").each(){
if($(this).attr("href") == '<%= *GET CURRENT PAGE* %>'){
$(this).parent("li").addClass("current");
}
}
Is this a good approach?
If it is, how can I get the current URL part like in the href?
If it isn't, what's your suggestion? :-)
FYI, the generated html I'm after:
<ul id="menu" class="lavaLampBottomStyle">
<li>
<a href="/KszEmployees/Index">Employees</a></li>
<li>
<a class="current" href="/">Customer</a></li>
</ul>
Upvotes: 13
Views: 15538
Reputation: 1895
I had the same problem. Using the following answers, I managed to put together the solution below.
https://stackoverflow.com/a/4733394/280972
https://stackoverflow.com/a/5650735/280972
In HtmlHelpers.cs:
public static class HtmlHelpers
{
public static HtmlString MenuLink(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
string controllerName
)
{
var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");
var link = htmlHelper.ActionLink(linkText, actionName, controllerName);
var prefix = (actionName == currentAction && controllerName == currentController) ? String.Format("<li class=\"current\">") : String.Format("<li>");
const string suffix = "</li>";
return new HtmlString(prefix + link + suffix);
}
}
In the layout:
<ul class="nav nav-list">
<li class="nav-header">Statistics</li>
@Html.MenuLink("Number of logins", "Logins", "Statistics")
</ul>
Note that the MenuLink-helper creates both the li-tag and the a-tag.
Feedback on this solution is very welcome!
Upvotes: 0
Reputation: 78152
If you want to do it all server-side, I've done this before. Create an action filter attribute:
public class PageOptionsAttribute : ActionFilterAttribute
{
public string Title { get; set; }
public string Section { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller as ControllerBase;
if (controller != null)
{
controller.SetPageSection(this.Section);
controller.SetPageTitle(this.Title);
}
base.OnActionExecuting(filterContext);
}
}
This calls two methods in my ControllerBase class that all my controllers inherit from:
public class ControllerBase : Controller
{
public void SetPageSection(string section)
{
// use the section defined or the controller name if none
ViewData["PageSection"] = section != null ?
section : this.RouteData.Values["controller"].ToString();
}
public void SetPageTitle(string title)
{
ViewData["PageTitle"] = title;
}
}
Set the title and page section on you controller methods:
public class HomeController : ControllerBase
{
[PageOptions(Title="Home Page", Section="Home")]
public ActionResult Index()
{ }
}
Then I call the ViewData value from my master page (this won't interfere with ViewData.Model):
<body class="<%=ViewData["PageSection"] %>">
Then to reference via CSS, instead of calling .current, give each nav item an ID and then use the body class in combination with that ID to determine the current page.
body.home #HomeNav { /* selected */ }
body.about #AboutNav { /* selected */ }
Upvotes: 15
Reputation: 8218
This should NOT be done with Javascript! Deciding which page you are on is the job of the server side code, it's not a UI behaviour.
Have the menu as a user control and pass a value to it to indicate which part of the menu should be highlighted. I'm front end person, not a .NET developer but something like this:
<yourControl:menuControl runat="server" ID="menu" selectedPage="4" />
Upvotes: -2
Reputation: 3680
That's probably the least intensive way of doing it. If you can count on the users to have javascript enabled, I see nothing wrong with this, and have done it myself on occasion.
Request.Url is the object you are interested in to get the current page on the server side. The suggestion to use window.location.href by tvanfosson isn't bad either if you want to keep it entirely clientside.
The advantage of using serverside, is that Request.Url has easily accessible parts of the url, such as Request.Url.Host, etc to help with your link-munging needs.
Upvotes: 6
Reputation: 532765
Extract the current location from window.location. Then use a selector that specifies the value of the href attribute to choose just those elements that match (presumably only one).
var currentLocation = window.location.href;
// probably needs to be massaged to extract just the path so that it works in dev/prod
$("#menu li a[href$="+currentLocation+"]").addClass("current");
Upvotes: 9