Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bobi 211 posts 583 karma points
    Mar 31, 2017 @ 21:24
    Bobi
    0

    How to make a dynamic menu

    I am looking to include my menu from the header inside the Master template page. However, because the menu is dynamic (if you are on the home page, then the home page menu item is highlighted; if you are on the contact us page, then the contact us page menu item is highlighted), I did not include the menu in the Master template.

    The website has grown in size, so it is very tedious to change any menu items (i.e. add to the menu). Are there any ways to include this type of dynamic menu (with class="active" in the list element) in the Master template, so that the class="active" is the only piece of code found on the specific page that is active?

  • Marc Goodson 617 posts 3810 karma points MVP 3x c-trib
    Apr 01, 2017 @ 11:39
    Marc Goodson
    1

    Hi Bobi

    Yes if you create a 'macro' for your menu (and there maybe an existing example implementation you can use to get started)

    The gist of it is to programmatically get a reference to your homepage and then loop through the children pages (going deeper if it's a mega menu) - if you give each document a check box called umbracoNaviHide you can use that value to decide whether to include the page or not....

    .... As you loop through each child item you can compare it's Id with the Id of the current page and if they are equal add the active class. If your site is quite deep in structure and the page you are on isn't in the menu - but you want to highlight as active the current section that is in the menu - then you can see whether the menu item is is included in the current page's path property (a list of all the IDs of the page's parents.)

    @{

    var homePage = Umbraco.TypedContentAtRoot().FirstOrDefault();

    }

      @foreach (var menuItem in homePage.Children().Where(f=>f.IsVisible()))} var activeClass = (menuItem.Id == Model.Content.Id) ? "active" : "";
    • @menuItem.Name
    • }

    (Typing on a mobile on a train - hope above makes sense!) Regards

    Marc

  • Bobi 211 posts 583 karma points
    Apr 01, 2017 @ 18:03
    Bobi
    0

    Thanks for the reply, and things make sense.

    So the code you posted would be used in the macro, but where would the actual menu code go?

    If the menu code is in the body tag of each page, where would the menu code go now, and how would the macro code be set up just to replace the class="active"?

    Below is a snippet of my menu code with for the homepage. You can see that this is a snippet of active page being home.

    <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse mega-menu navbar-responsive-collapse">
            <div class="container">
                <ul class="nav navbar-nav">
                    <!-- Home -->
                    <li class="active">
                        <a href="/" class="dropdown-toggle">
                            Home
                        </a>
                    </li>
                    <!-- End Home -->
    ... [the rest of menu items, about page, etc. that do not have the class = "active"]
    
  • Marc Goodson 617 posts 3810 karma points MVP 3x c-trib
    Apr 03, 2017 @ 19:00
    Marc Goodson
    1

    Hi Bobi

    you need to remove all of your code for building the navigation as you have it in the example from each page, and replace it with the macro code in the master template view.

    So your master template view would now have something along the lines of

    <html>
    <head>
    <!-- all your header stuff -->
    </head>
    <body>
    <div class="container">
    @Umbraco.RenderMacro("SiteNavigation")
    
    @RenderBody()
    </div>
    </body>
    </html>
    

    and then the contents of your 'SiteNavigation' macro would looks something like this:

    @inherits Umbraco.Web.Macros.PartialViewMacroPage
    @{ 
        var homePage = Umbraco.TypedContentAtRoot().FirstOrDefault();
        var menuPages = homePage.Children().Where(f=>f.IsVisible());
        var isHomePage = homePage.Id == Model.Content.Id;
     }
      <div class="collapse navbar-collapse mega-menu navbar-responsive-collapse">
            <div class="container">
                <ul class="nav navbar-nav">
                    <li class="@(isHomePage ? "active" : string.Empty)"><a href="@homePage.Url">@homePage.Name</a></li>
        @foreach (var item in menuPages)
        {
            //set active class if current page is in this section
            var activeClass = !isHomePage && Model.Content.Path.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Contains(item.Id.ToString()) ? "active" : string.Empty;
            <li class="@activeClass">
                <a href="@item.Url">@item.Name</a>
            </li>
        }
    </ul>
        </div>
        </div>
    

    There are lots of different approaches to writing this kind of code in Umbraco (dynamic vs strongly typed vs ModelsBuilder) and you could use a Html.Partial instead of an Umbraco Macro.

    But the gist is the same, you encapsulate your menu functionality into a reusable piece of code that runs on each page and puts the active class on the current section / menu item.

    regards

    Marc

  • Bobi 211 posts 583 karma points
    Apr 03, 2017 @ 19:29
    Bobi
    0

    Hi Marc,

    Thanks for the detailed reply!

    So what does that loop do, and would it be included for each menu item (i.e. for the about page, the contact page, etc.)?

    Also, how does the umbracoNaviHide checkbox add to this? If I include that on each document type, would all of the menu pages (home, contact, about, etc.) need to have that checked?

    Thanks :)

  • Marc Goodson 617 posts 3810 karma points MVP 3x c-trib
    Apr 04, 2017 @ 08:28
    Marc Goodson
    0

    Hi Bobi

    When I get the list of menuPages to loop through I pass the filter f=>f.IsVisible() this will only return pages that don't have their umbracoNaviHide checkbox checked.

    So if you add that checkbox property to your document types it's an opt out of the menu rather than an opt in.

    The macro containing the loop, because it's referenced in your site master view, would execute on every single page, producing customised markup for each page (eg the active class in the right place).

    So your about page will no longer have the html for the navigation menu, but when you load it, the navigation will appear (from the master view) and it will have the active class on the about page item, because when writing out the menu in the loop the check whether the current page's path (list of all parent ids) contains the menu items id will be true.

    regards

    Marc

Please Sign in or register to post replies

Write your reply to:

Draft