OK new to MVC. I had asked this question earlier and got an answer but I am wondering if there is a simpler solution.
Say I have a master page with a menu laid out as an unordered list. How would I go about setting a css class on the currently selected menu item?
EDIT:
I am using the menu just as it comes setup out of the box when you start a new mvc app
<ul id="menu">
<li><%: Html.ActionLink("Home", "Index", "Home")%></li>
<li><%: Html.ActionLink("About", "About", "Home")%></li>
</ul>
The answer from Jakub Konecki led me in the right direction... here is the controller action I ended up with:
[ChildActionOnly]
public ActionResult MainMenu()
{
var items = new List<MenuItem>
{
new MenuItem{ Text = "Home", Action = "Index", Controller = "Home", Selected=false },
new MenuItem{ Text = "My Profile", Action = "Index", Controller = "Profile", Selected = false},
new MenuItem{ Text = "About", Action = "About", Controller = "Home", Selected = false }
};
string action = ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString();
string controller = ControllerContext.ParentActionViewContext.RouteData.Values["controller"].ToString();
foreach (var item in items)
{
if (item.Controller == controller && item.Action == action)
{
item.Selected = true;
}
}
return PartialView(items);
}
Hope this helps someone.
You should pass all relevant information in the Model. Ideally your menu will be rendered as a Partial View by a separate controller method. I have a Navigation controller with actions like MainMenu, FooterMenu, Breadcrumbs, etc that render individual parts.
Your model will be a collection of menu items like:
public class MenuItemModel
{
public MenuItemModel()
{
SubMenu = new List<MenuItemModel>();
}
public string Text { get; set; }
public string Controller { get; set; }
public string Action { get; set; }
public bool Selected { get; set; }
public List<MenuItemModel> SubMenu { get; private set; }
}
Your Controller will create a collection of menu items and pass them to the view with the appropriate item selected. Then the view can be as simple as:
<ul id="menu">
<% foreach(var menuItem in Model.MenuItems) { %>
<li><%: Html.ActionLink(menuItem.Text, menuItem.Action, menuItem.Controller, null, new { @class = menuItem.Selected ? "selected" : "" })%></li>
<% } %>
</ul>
stephen,
here's my contribution to the party. a recursive inline function to populate the <ul><li>
for as many depths as is required (here's the entire ascx file):
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<GBC_Art.Controllers.MenuItemModel>>" %>
<%@ Import Namespace="GBC_Art.Controllers" %>
<%
Action<List<MenuItemModel>, int> printNodesRecursively = null;
printNodesRecursively = (List<MenuItemModel> nodeList, int depth) =>
{
if (nodeList == null || nodeList.Count == 0) return;
%>
<ul<%= depth == 0 ? " id='menu'" : ""%>>
<%
foreach (var menuItem in nodeList)
{
%>
<li><%= Html.ActionLink(menuItem.Text, menuItem.Action, menuItem.Controller, null, new { @class = menuItem.Selected ? "selected" : "" })%>
<%printNodesRecursively(menuItem.SubMenu, depth + 1);%>
</li>
<%
}
%>
</ul>
<%
};
List<MenuItemModel> nodes = Model;
printNodesRecursively(nodes, 0);
%>
usage -> called as a partialview via the controller as per your example above.
cheers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With