0

Using one of the ASP.Net MVC5 templates, how can I maintain menu selection when selecting an item from a multi-level menu?

When a sub-menu is clicked, the page loads but there is no indication which menu item has been clicked. It is possible to expand the menu and eventually it will show the indicator but how can this be set as default behaviour?

If the user clicks on a root-level menu item, after the page loads, there is clear indication which menu item has been clicked.

weblar83
  • 681
  • 11
  • 32

1 Answers1

1

One way to solve this solution would be to add another property to each view to specify the sub-menu item page name, pass the sub-menu item page name to the TopMenu view component then set the active CSS class for the appropriate sub-menu item.

There are many other ways to solve this question but this approach seems to be fairly quick and easy given the template has already created the framework to use for the root-level navigation; we are simply extending it.

The following steps will walk you though this approach:

Step 1

Add a property to each view that specifies the currently active sub-menu item name. The following snippet is an example of what the top of each view page could look like.

@{
  ViewBag.CurrentPageName = "Reporting";
  ViewBag.CurrentSubPageName = "Activity Report";
}

Step 2

Add a property, in this case ActiveSubMenuItemName, to the TopMenuViewModel class to store the currently active sub-menu item name.

public class TopMenuViewModel
{
  public UserMenu MainMenu { get; set; }
  public string ActiveMenuItemName { get; set; }
  public string ActiveSubMenuItemName { get; set; }
}

Step 3

Add a parameter to the InvokeAsync method in the TopMenuViewComponent class to accept the currently active sub-menu item name.

public async Task<IViewComponentResult> InvokeAsync(string activeMenu = "", string activeSubMenu = "")
{
  var model = new TopMenuViewModel
  {
    MainMenu = await _userNavigationManager.GetMenuAsync("MainMenu", _abpSession.ToUserIdentifier()),
    ActiveMenuItemName = activeMenu,
    ActiveSubMenuItemName = activeSubMenu
  };

  return View(model);
}

Step 4

Pass the property we set at the top of each view in step 1 into the method we updated in step 4.

<ul class="nav navbar-nav">
  @await Component.InvokeAsync(typeof(TopMenuViewComponent), new { activeMenu = ViewBag.CurrentPageName,  activeSubMenu = ViewBag.CurrentSubPageName })
</ul>

Step 5

Update the Views/Shared/Components/TopMenu/Default.cshtml view to set the active class within the dropdown-menu for the currently active sub-menu item.

<ul class="dropdown-menu">
  @foreach (var subMenuItem in menuItem.Items) {
    <li class="@(Model.ActiveSubMenuItemName == subMenuItem.Name ? "active" : "")">
      <a href="@calculateMenuUrl(subMenuItem.Url)">
        @if (!string.IsNullOrWhiteSpace(subMenuItem.Icon))
        {
            <i class="@subMenuItem.Icon"></i>
        }
        @subMenuItem.DisplayName
      </a>
    </li>
  }
</ul>
Jesse Johnson
  • 1,638
  • 15
  • 25