Copied to clipboard

Flag this post as spam?

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


  • Bobi 346 posts 950 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 2138 posts 14321 karma points MVP 8x c-trib
    Apr 01, 2017 @ 11:39
    Marc Goodson
    2

    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 346 posts 950 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 2138 posts 14321 karma points MVP 8x c-trib
    Apr 03, 2017 @ 19:00
    Marc Goodson
    101

    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 346 posts 950 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 2138 posts 14321 karma points MVP 8x c-trib
    Apr 04, 2017 @ 08:28
    Marc Goodson
    1

    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

  • Bobi 346 posts 950 karma points
    Mar 07, 2019 @ 16:57
    Bobi
    0

    Hi Marc, I finally got around to trying to implement this on a site, but I'm running into a lot of formatting issues.

    In the example you provided using my css codes, everything works great (i.e., the highlighted page is the current page); however, it lists all menu items without being hidden in a dropdown.

    It should appear like so: Home About - About Us, People, Careers, Terms of Use, Privacy Policy --> these are all in a dropdown list when you hover over "About". But, About Us, People, Careers, Terms of Use, and Privacy Policy are not children of about within umbraco but instead all of these pages are children of the "Home" tab.

    The only other menu item that does not have a dropdown is the Blog (articulate) menu item.

    How can I implement this dropdown aspect while maintaining the active status?

    Here is the code snippet of some of the menu:

    <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 -->
                <!-- About -->
                <li class="dropdown">
                    <a href="javascript:void(0);" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
                        About
                    </a>
                    <ul class="dropdown-menu" role="menu">
                        <!-- About Us -->
                        <li>
                            <a href="/about-us/">About Us</a>
                        </li>
                        <!-- About Us -->
                        <!-- People -->
                        <li>
                            <a href="/about-our-team/">People</a>
                        </li>
                        <!-- End People -->
                        <!-- Careers -->
                        <li>
                            <a href="/careers/">
                                Careers
                            </a>
                        </li>
                        <!-- End Careers -->
                        <!-- Terms of Use -->
                        <li><a href="/terms/">Terms of Use</a></li>
                        <!-- End Terms of Use -->
                        <!-- Privacy Policy -->
                        <li><a href="/privacy-policy/">Privacy Policy</a></li>
                        <!-- End Privacy Policy -->
                    </ul>
                </li>
                <!-- End About -->  </ul>
        </div><!--/end container--> </div>
    
Please Sign in or register to post replies

Write your reply to:

Draft