Mvc Dynamic Menu Simple Text Overlay

I created a recursive N-level dynamic menu method that creates a menu.

enter image description here

As you can see in the picture above, the content is returned to the ParialView with the name "_Menu.cshtml", and this Partial View file is empty.

enter image description here

and then there is _LayoutPage.Cshtml

<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div> <div> <input type="text" id="txtSearch" /> <button id="btnSearch">Search</button> </div> <div id="Menu"> @{Html.RenderAction("_Menu", "Home"); } @Html.Partial("_Menu") </div> <div> @RenderBody() </div> </div> </body> </html> 

it successfully places the result in a browser, but like plain text, as I mentioned above, and can be seen below.

enter image description here

How can I make them act as links and not as plain text? Help will be appreciated. Thanks:)

+1
source share
2 answers

I took a slightly more active view of this.

In the layout I put ...

  @if (Model != null && Model is Core.Objects.Entities.CMS.Page) { @Html.Action("Menu", new MenuOptions { IsRootMenu = true, ForPageId = Model.Id, Depth = 3 }) } 

First, I check whether the user is registered and, therefore, โ€œon a managed pageโ€, which happens only if the model has a certain type โ€œCore.Objects.Entities.CMS.Pageโ€.

Then I call @ Html.Action, which calls the next child action on my controller, and I create my menu options ...

 [HttpGet] [ChildActionOnly] [Route("~/Menu")] public ActionResult Menu(MenuOptions options) { //TODO: consider other complex menuing scenarios like a popup / tree based structures // New api calls may be needed to support more complex menuing scenarios // TODO: figure out how to build these, perhaps with a string builder var expand = string.Empty; if (options.Depth > 0) { switch (options.Depth) { case 1: expand = "?$expand=PageInfo,Pages($expand=PageInfo)"; break; case 2: expand = "?$expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo))"; break; case 3: expand = "?$expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo)))"; break; case 4: expand = "?$expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo,Pages($expand=Pages($expand=PageInfo))))"; break; case 5: expand = "?$expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo,Pages($expand=PageInfo)))))"; break; } } var query = options.IsRootMenu ? "Core/Page/MainMenuFor(id=" + options.ForPageId + ")" + expand : "Core/Page/ChildrenOf(id=" + options.ForPageId + ")" + expand; var items = Task.Run(() => Api.GetODataCollection<Page>(query)).Result; return PartialView(new MenuViewModel { Origin = options.ForPageId, Pages = items }); } 

In my case, this area needs a little work, and I probably should replace this case statement with a more reasonable loop loop that builds the query.

In short, although all of this does, itโ€™s pulling the hierarchy of page objects from my OData API to the depth, determined by my parameters passed in the form of a menu, usually change, some of them are parameters of the same level, others go to several levels, but I wanted to use a reusable menu system.

Having done this, I can take the OData result and build a model for the menu view, which looks like this:

 @model MenuViewModel @if (Model.Pages != null) { <ul class="menu"> @foreach (var p in Model.Pages) { Html.RenderPartial("MenuItem", new MenuItemViewModel { Page = p, Origin = Model.Origin }); } </ul> } 

The menu views set the list for the root and display the children for each child page, I plan at some point to expand this view for things like spitting out the parent page, which may be the result of the OData that I pulled into the controller.

And the last piece of the puzzle is a menu item view that deals with the rendering of each individual menu item ...

 @model MenuItemViewModel <li> <a href="@Html.Raw("/" + Model.Page.Path)" @CurrentItem(Model.Page)>@Html.PageInfo(Model.Page).Title</a> @if (Model.Page.Pages != null && Model.Page.Pages.Any()) { <ul class="submenu"> @foreach (var p in Model.Page.Pages) { Html.RenderPartial("MenuItem", new MenuItemViewModel { Page = p, Origin = Model.Origin }); } </ul> } </li> @functions{ MvcHtmlString CurrentItem(Core.Objects.Entities.CMS.Page p) { if (Model.Origin == p.Id) return new MvcHtmlString("class='selected'"); return null; } } 

Having done all this, I end up with a nested set of lists, then I use CSS to handle things like pop-ups or dynamic ect extensions.

This functionality is not quite complete, I need to make sure that I handle the "marking of the current element" with a class or something else, so I can style it differently, and there are several other menu scripts that I would like to add, but also I considered reusing this html structure in some way for tree views, but trees may be a bit more involved in the longer term, but doing things like putting an image next to menu items seems to be good a big improvement in logic, if configured :)

The last thing I forgot to put before is the menu options model used in the menu action in the controller ...

 public class MenuOptions { public bool IsRootMenu { get; set; } public int ForPageId { get; set; } public int Depth { get; set; } } 
+2
source

Although the war has resolved my request above. But I still want to be responsible for people for whom the answer above seems complicated. The easiest way in MVC is to populate a dynamic navigation menu from a database.

in the controller:

  public ActionResult Index() { Menu menu_ = new Menu(); ViewBag.Menu = menu_.getMenuList(); return View(); } 

in _layoutpage.Cshtml

  <div id="Menu"> @{ List<WebApplicationMVC.Core.Models.menu> All = ViewBag.Menu;} <ul> @foreach (var One in All.Where(m => m.ParentId == 0)) { List<WebApplicationMVC.Core.Models.menu> Child = All.Where(m => One.id == m.ParentId).ToList(); if (Child.Count > 0) { if(One.ActionLink == "Yes") { <li> @Html.ActionLink(One.Name, One.Action, One.Controller) @SubMenu(One, All) </li> } else { <li> @One.Name; @SubMenu(One, All) </li> } } else { <li>@Html.ActionLink(One.Name, One.Action, One.Controller)</li> } } </ul> @helper SubMenu(WebApplicationMVC.Core.Models.menu Object, List<WebApplicationMVC.Core.Models.menu> List) { List<WebApplicationMVC.Core.Models.menu> subChilds = (from a in List where Object.id == a.ParentId select a).ToList(); <ul> @foreach (var subOne in subChilds) { List<WebApplicationMVC.Core.Models.menu> InnerChilds = (from a in List where subOne.id == a.ParentId select a).ToList(); if (InnerChilds.Count > 0) { if (subOne.ActionLink == "Yes") { <li> @Html.ActionLink(subOne.Name, subOne.Action, subOne.Controller) @SubMenu(subOne, List) </li> } else { <li> @subOne.Name @SubMenu(subOne, List) </li> } } else { <li>@Html.ActionLink(subOne.Name, subOne.Action, subOne.Controller)</li> } } </ul> } </div> 
+4
source

Source: https://habr.com/ru/post/987123/


All Articles