I have seen several examples on creating a HTML helper method for active
menu items.
**Summary:**
Simply put, in an MVC project, using the Twitter Bootstrap, I am trying to preserve the open state of a collapsible menu when a child is selected.
I am using a collapsible menu, where the parent's css (the selected item) needs to include active open
if a child is selected. This will ensure that the menu is open at the right location. With the use of another HTML helper, the active item is already set to active
.
HTML for the menu:
<div id="sidebar">
<ul>
<li class="active"><a href="dashboard.html"><i class="icon-home"></i> <span>Dashboard</span></a></li>
<li class="submenu">
<a href="#"><i class="icon-beaker"></i> <span>UI Lab</span> <i class="arrow icon-chevron-right"></i></a>
<ul>
<li><a href="interface.html">Interface Elements</a></li>
<li><a href="jquery-ui.html">jQuery UI</a></li>
<li><a href="buttons.html">Buttons & icons</a></li>
</ul>
</li>
<li class="submenu">
<a href="#"><i class="icon-th-list"></i> <span>Form elements</span> <i class="arrow icon-chevron-right"></i></a>
<ul>
<li><a href="form-common.html">Common elements</a></li>
<li><a href="form-validation.html">Validation</a></li>
<li><a href="form-wizard.html">Wizard</a></li>
</ul>
</li>
<li><a href="tables.html"><i class="icon-th"></i> <span>Tables</span></a></li>
<li><a href="grid.html"><i class="icon-th-list"></i> <span>Grid Layout</span></a></li>
<li class="submenu">
<a href="#"><i class="icon-file"></i> <span>Sample pages</span> <i class="arrow icon-chevron-right"></i></a>
<ul>
<li><a href="invoice.html">Invoice</a></li>
<li><a href="chat.html">Support chat</a></li>
<li><a href="calendar.html">Calendar</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="messages.html">Messages</a></li>
</ul>
</li>
<li>
<a href="charts.html"><i class="icon-signal"></i> <span>Charts & graphs</span></a>
</li>
<li>
<a href="widgets.html"><i class="icon-inbox"></i> <span>Widgets</span></a>
</li>
</ul>
</div>
Here is the helper method for items:
public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper,
string text,
string action,
string controller,
string iconClass)
{
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
var i = new TagBuilder("i");
i.AddCssClass(iconClass);
var basePath = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
//li.InnerHtml = htmlHelper.ActionLink("<i>something</i>" + text, action, controller).ToHtmlString();
li.InnerHtml = htmlHelper.Raw(string.Format("<a href=\"{0}/{1}/{2}\"><i class=\"{4}\"></i>{3}</a>", basePath, controller, action, text, iconClass)).ToString();
return MvcHtmlString.Create(li.ToString());
}
And implemented like this:
<div id="sidebar">
<ul>
@Html.MenuItem("Dashboard", "Index", "Dashboard", "icon-home")
@* <li class="active"><a href="dashboard.html"><i class="icon-home"></i> <span>Dashboard</span></a></li>*@
<li class="submenu">
<a href="#"><i class="icon-beaker"></i> <span>UI Lab</span> <i class="arrow icon-chevron-right"></i></a>
<ul>
<li>@Html.MenuItem("Websites", "Index", "Websites", null)</li>
<li><a href="jquery-ui.html">jQuery UI</a></li>
<li><a href="buttons.html">Buttons & icons</a></li>
</ul>
</li>
<li class="submenu">
<a href="#"><i class="icon-th-list"></i> <span>Form elements</span> <i class="arrow icon-chevron-right"></i></a>
<ul>
<li><a href="form-common.html">Common elements</a></li>
<li><a href="form-validation.html">Validation</a></li>
<li><a href="form-wizard.html">Wizard</a></li>
</ul>
</li>
So what I don't have is something for the submenu items.
Is there a simpler way of trying to accomplish this?
–UPDATE–
I'm guessing that putting this into a partial view may be best. I need to find some way to preserve the selected item on click to reference it on every menu item, rather than check if the controller/action matches in order to set the current item to "active". A controller method that activates on click, checks if the currently selected item is a parent or child, and if the parent matches a child, then format differently? I'm sure there has to be an easier way.
Best Solution
Alright, so here is one solution I came up with.
To recap, this isn't as simple as adding an "active" CSS class to an item if it is selected (as per the default Bootstrap MVC. In this solution we need to identify the parent of and a child and identify both.
Default page is Dashboard. The user then clicks on "Configuration" to expand the menu, then selects the "Websites" link which opens the page.
Here is the solution:
Model:
Controller:
Shared View:
Implementation in the view:
The controller checks if the current action/controller names match one on the menu and if so, set
selected = true
. In the partial view, there is some logic to determine the display structure, based on the parent/child relationships, and if a child is selected, so is the parent.In brief, that's it. I'd like to hear some comments/other examples.