Copied to clipboard

Flag this post as spam?

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


  • Bendik Engebretsen 105 posts 202 karma points
    Feb 29, 2016 @ 09:29
    Bendik Engebretsen
    0

    Multilevel menu in the Fanoe starter kit

    I'm desiging a website that needs to have multiple levels in the menu. But this doesn't seem to work with the Fanoe starter kit.

    First, I made "Text Page" an allowed child node type of the "Text Page" document type. I am then able to create a Text Page nested under an other Text Page. And this seems to render fine in the html, I can see I get a sublevel ul tag in the menu:

    <ul sublevel level-4>...</ul>
    

    So this means that MainNavigation.cshtml is functioning correctly (recursively adding child menu items).

    But when hovering over the parent menu item nothing happens. Is there maybe some js and css that must be modified to accomplish this?

  • M T 35 posts 212 karma points
    Feb 29, 2016 @ 10:13
    M T
    1

    Hi Bendik

    This is what I use for my navigation, I can't remember but I believe i just slightly tweaked the Fanoe nav code. It does what i want however i had to create a different nav for mobile devices as it doesnt work so well on touch devices with multiple levels.

    <nav id="site-navigation" class="main-navigation" role="navigation">
                            @if (home.Children.Any())
                            {
                            @* Get the first page in the children *@
                            var naviLevel = home.Children.First().Level;
    
                            @* Add in level for a CSS hook *@
                            <ul class="level-@naviLevel nav-menu" style="float: left;">
                                @* For each child page under the home node *@
                                @foreach (var childPage in home.Children)
                                {
                                if (childPage.Children.Any())
                                {
                                <li class="has-child @(childPage.IsAncestorOrSelf(CurrentPage) ? " selected" : null)">
                                    @if (childPage.Children.Any())
                                    {
                                    <span><a href="@childPage.Url">@childPage.Name</a></span>
                                    @childPages(childPage.Children)
                                    }
                                    else
                                    {
                                    <span><a href="@childPage.Url">@childPage.Name</a></span>
                                    }
                                </li>
                                }
                                else
                                {
                                <li class="@(childPage.IsAncestorOrSelf(CurrentPage) ? " selected" : null)">
                                    <span><a href="@childPage.Url">@childPage.Name</a></span>
                                </li>
                                }
                                }
                            </ul>
                            }
                            @helper childPages(dynamic pages)
                            {
                            @* Ensure that we have a collection of pages *@
                            if (pages.Any())
                            {
                            @* Get the first page in pages and get the level *@
                            var naviLevel = pages.First().Level;
    
                            @* Add in level for a CSS hook *@
                            <ul class="sublevel level-@(naviLevel)">
                                @foreach (var page in pages)
                                {
                                <li>
                                    <a href="@page.Url">@page.Name</a>
                                    @* if the current page has any children *@
                                    @if (page.Children.Any())
                                    {
                                    @* Call our helper to display the children *@
                                    @childPages(page.Children)
                                    }
                                </li>
                                }
                            </ul>
                            }
                            }
                        </nav>
    

    Then this simple bit of CSS will get it to display on hover.

    nav .has-child:hover > .sublevel {
        display: block;
    }
    

    For mobile you will need some custom js/jQuery to get what you want but here's mine.

    /* nav functions */
    
    $(window).scroll(function(){
        if( $(this).scrollTop() >= 95 ) {
        console.log("pinned");
        $(".right-headerwidgets").addClass("pin");
        $(".main-navigation").addClass("pin");
    
        } else {
        $(".right-headerwidgets").removeClass("pin");
        $(".main-navigation").removeClass("pin");
        console.log("unpinned");
    
      }
    });
    
    
    $(document).ready(function($){  
        $("#toggle").on("click", function(){
            $(".nav-menu").slideDown(".nav-menu");
            $("nav").toggleClass("open");
            $('.cross').toggleClass('open');
            $('.toggle').toggleClass('open');   
        });
    });
    
  • Bendik Engebretsen 105 posts 202 karma points
    Feb 29, 2016 @ 11:45
    Bendik Engebretsen
    0

    Thanks for helping!

    I couldn't really see the difference between you code and the original, but by taking a closer look at the CSS, I realized that the submenu li-items that have a submenu must also have the "has-child" class. So Here is my code now:

        @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    @{ var home = CurrentPage.Site(); }
    
    @if (home.Children.Any())
    {
        @* Get the first page in the children *@
        var naviLevel = home.Children.First().Level;
    
        @* Add in level for a CSS hook *@
        <ul class="level-@naviLevel">            
            @* For each child page under the home node *@
            @foreach (var childPage in home.Children)
            {   
                if (childPage.Children.Any())
                {                    
                    <li class="has-child @(childPage.IsAncestorOrSelf(CurrentPage) ? "selected" : null)">
                        @if(childPage.DocumentTypeAlias == "LandingPage") 
                        {
                            <span>@childPage.Name</span>
                            @childPages(childPage.Children)
                        } else {
                            <a href="@childPage.Url">@childPage.Name</a>
                        }
                    </li>
                } 
                else
                {
                    <li class="@(childPage.IsAncestorOrSelf(CurrentPage) ? "selected" : null)">
                        <a href="@childPage.Url">@childPage.Name</a>
                    </li>
                }            
            }
        </ul>
    }
    
    @helper childPages(dynamic pages)
    {
        @* Ensure that we have a collection of pages *@
        if (pages.Any())
        {
            @* Get the first page in pages and get the level *@
            var naviLevel = pages.First().Level;
    
            @* Add in level for a CSS hook *@
            <ul class="sublevel level-@(naviLevel)">
                @foreach (var page in pages)
                {
                    <li class="@(page.Children.Any() ? "has-child" : "")">
                        <a href="@page.Url">@page.Name</a>
    
                        @* if the current page has any children *@
                        @if (page.Children.Any())
                        {
                            @* Call our helper to display the children *@
                            @childPages(page.Children)
                        }
                    </li>
                }
            </ul>
        }
    }
    

    This makes the sub-sub-menu (level-4) show up when hovering, but I am unable to hover over to the sub-sub-menu, because moving outside the sub-menu makes it all disappear. Does anybody know how to modify the CSS so that it sticks?

  • M T 35 posts 212 karma points
    Feb 29, 2016 @ 12:04
    M T
    1

    here you go :-

        .level-3 li:hover > .level-4 {
        display: block;
    }
    

    If you have any trouble with this you probably have a gap between the submenu's which would cause you to loose your :hover. typically this would be a margin, if you have this issue use padding rather than margin.

    or alternatively

    box-sizing: margin-box;
    

    M

  • Bendik Engebretsen 105 posts 202 karma points
    Feb 29, 2016 @ 12:55
    Bendik Engebretsen
    0

    Thanks Matt! I've got it working now:-) But a new problem arises: if the level-4 menu is shown on the rightmost level-3 menuitem, it may be outside the browser window and unreachable. Is there a trick to make it appear to the left instead, when its boundaries exceed the browser window?

    Also, my skills in js/jquery are not the best, so I can't figure out how to modify the fanoe.js to get multiple levels in the mobile menu. The (original) code is like this:

    (function($) {
    
      // Making elements equal height
        var equalheight = function(container){
    
          var currentTallest = 0,
            currentRowStart = 0,
            rowDivs = new Array(),
            $el,
            topPosition = 0;
    
          $(container).find('.equal').each(function() {
    
            $el = $(this);
            $($el).height('auto')
            topPostion = $el.position().top;
    
            if (currentRowStart != topPostion) {
              for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) {
                  rowDivs[currentDiv].height(currentTallest);
            }
              rowDivs.length = 0; // empty the array
              currentRowStart = topPostion;
              currentTallest = $el.height();
              rowDivs.push($el);
            } else {
              rowDivs.push($el);
              currentTallest = (currentTallest < $el.height()) ? ($el.height()) : (currentTallest);
            }
            for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) {
              rowDivs[currentDiv].height(currentTallest);
            }
          });
        };
    
      // Check for window width before resizing
      function equalHeightChecker () {
        if ( window.innerWidth > 767 && !heightIsSet ) {
          $('.equalizer')
            .each(function(){
              equalheight(this);
              heightIsSet = true;
            });
        }
        else if (window.innerWidth<768 && heightIsSet) {
          $('.equalizer')
            .each(function(){
              $(this).find('.equal').each(function () {
                this.style.height = 'auto';
              });
              heightIsSet = false;
            });
        }
      }
    
      // Initialize equal height script
      var heightIsSet;
    
      // On load
      $(window).load(function() {
       equalHeightChecker();
      });
    
      // and on resize
      $(window).resize(function(){
        equalHeightChecker();
      });
    
      // Navigation
      $('#toggle').click(function(){
        $('.has-child').removeClass('selected');
        $('nav').toggleClass('open');
        $('.cross').toggleClass('open');
      });
    
      $('.has-child').click(function(){
        if ( window.innerWidth < 768 ) {
          if ( $( this ).hasClass('selected')){
            $('.has-child').removeClass('selected');    
          } else {
            $('.has-child').removeClass('selected'); 
            $(this).toggleClass('selected');
          }
        }
      });
    
    })(jQuery);
    

    (I'm starting to realize that the project is maybe stretching the Fanoe design a bit too much, and that there is a good reason that the originators of Fanoe opted the multilevel menus out.)

  • M T 35 posts 212 karma points
    Feb 29, 2016 @ 13:15
    M T
    0

    No problem, I had the same issue when I first started using Umbraco, but its all good for learning. Over time you will build your own "starter kit".

    You will need to fiddle the css. without looking at your website its hard to tell exactly what you need, I'm guessing absolute positioning will be your saviour, Its one of those mess around in chrome developer tools until it works jobs.

    As for the mobile nav... Now there is no easy way around this it takes a fair bit of custom css and jQuery which is why I mentioned you may want a separate nav partial for mobile. Personally that's the route I would go down as you can structure your html better for mobile. But it's up to you, trial and error my friend!

    Here's two resources I found useful when learning CSS and JQuery.

    https://css-tricks.com/

    https://www.codecademy.com/learn/jquery

    Regards & Good luck M

  • Bendik Engebretsen 105 posts 202 karma points
    Feb 29, 2016 @ 14:47
    Bendik Engebretsen
    0

    Thanks again Matt. I have realized that this project is too ambitious for my skills in CSS/jquery, so I will stick to one sublevel menus only. And maybe it's for the better, after all, the structure will probably be easier to understand for our users.

    (Of course, one could always hope that the Umbraco team implements it in a future release of Fanoe...)

  • M T 35 posts 212 karma points
    Feb 29, 2016 @ 16:23
    M T
    0

    A wise decision, after your 2nd level of nav i think its better to actually navigate via links on the page. Also means your users wont skip pages.

    Good luck! M

Please Sign in or register to post replies

Write your reply to:

Draft