Kentico 12 MVC - create dropdown menu navigation

Petline developer asked on April 26, 2019 21:17

What would be best practice to create menu navigation with sub levels. I created the dynamic menu navigation using the Kentico documentation for MedioClinic training example, the problem is that it creates only the first level, it doesn't check if there are any children to that level.

for example, if I created dynamic menu navigation that looks like that:


  • Home

  • Our Story

    *   About us
    
    *   Contact us        
    

I want to see that structure, instead it just display all the items on same level.

This is a Kentico 12 MVC, so please make sure it is relevant to that. thanks.

Correct Answer

Zach Perry answered on April 26, 2019 21:39

Here is basically how I did it, just cache the call to get this data. Might be an easier way to do this but I had some other needs to do it this way.

 public static List<TreeNode> GetPages()
        {
            var selparams = new NodeSelectionParameters
            {
                //Page Types to show in Nav Menu 
                ClassNames = "Custom.Page;Custom.OtherPageType",
                Where = "NodeLevel = 1",
                SelectOnlyPublished = true
            };
            return DocumentHelper.GetDocuments(selparams, new TreeProvider()).Items.ToList();
        }


         private List<NavLinks> GetLinks()
    {
        var pages = PageHelper.GetPages();
        var result = new List<NavLinks>();

        foreach (var page in pages)
        {
            if (page.GetValue("ShowInMainNav", false))
            {
                var children = new List<NavLinks>();
                if (page.Children.Count > 0)
                {
                    children = GetChildren(page);
                }

                var url = page.NodeAliasPath;


                result.Add(new NavLinks
                {
                    Children = children,
                    DisplayName = page.GetValue("DisplayName",""),
                    Url = url
                });
            }
        }
        return result;
    }

    private List<NavLinks> GetChildren(TreeNode page)
    {
        var result = new List<NavLinks>();
        var children = page.Children.WithAllData;
        foreach (var child in children)
        {
            if (child.GetValue("ShowInMainNav", false))
            {
                var subchildren = new List<NavLinks>();
                if (child.Children.Count > 0)
                {
                    subchildren = GetChildren(child);
                }
                var url = child.NodeAliasPath;


                result.Add(new NavLinks
                {
                    Children = subchildren,
                    DisplayName = child.GetValue("DisplayName", ""),
                    Url = url
                });
            }

        }

        return result;
    }

And in the view:

 @helper Menu(NavLinks link)
                {
                    var links = link.Children;
                <ul class="submenu">
                    <li><a class="" href="@link.Url">Overview</a></li>

                    @foreach (var child in links)
                    {
                        <li>
                            <a class="" href="@child.Url">@child.DisplayName</a>
                            @if (child.Children.Count > 0)
                            {
                                @Menu(child)
                            }
                        </li>
                    }
                </ul>

                }
                @foreach (var link in Model.Links)
                {
                    <li class="">
                        <a class="" href="@link.Url">
                            @link.DisplayName
                        </a>
                        @if (link.Children.Count > 0)
                        {
                            @Menu(link)
                        }

                    </li>
                }
1 votesVote for this answer Unmark Correct answer

Recent Answers


Dmitry Bastron answered on April 28, 2019 16:32

Hi,

This is the solution I used on my recent project. Assuming that:

NavigationLink is your PageType to store navigation links and they can be nested

And the following extra properties can be added to the partial class:

public partial class NavigationLink
{
    public IEnumerable<NavigationLink> ChildLinks { get; set; }
    public NavigationLink ParentLink { get; set; }
}

The following code will (if you pass /my-navigation-path/% as path) will cache and return you navigation links tree

public class NavigationRepository : INavigationRepository
{
    private readonly string _baseCacheKey = $"custom|navigation";

    public List<NavigationLink> GetNavigationLinksByPath(string path)
    {
        var cacheKey = $"{_baseCacheKey}|{path}";

        var result = new List<NavigationLink>();

        using (var cs = new CachedSection<List<NavigationLink>>(ref result, CacheHelper.CacheMinutes(SiteContext.CurrentSiteName), true, cacheKey))
        {
            if (cs.LoadData)
            {
                var tempResult = NavigationLinkProvider.GetNavigationLinks()
                    .Path(path)
                    .OnSite(SiteContext.CurrentSiteName)
                    .ToList();

                foreach (var navigationLink in tempResult)
                {
                    navigationLink.ChildLinks = tempResult.Where(x => x.NodeParentID == navigationLink.NodeID)
                        .OrderBy(x => x.NodeOrder)
                        .ToList();
                    foreach (var childLink in navigationLink.ChildLinks)
                    {
                        childLink.ParentLink = navigationLink;
                    }
                }

                result = tempResult.Where(x => x.ParentLink == default(NavigationLink)).ToList();

                var cacheDependencies = new List<string>
                {
                    $"nodes|{SiteContext.CurrentSiteName}|{NavigationLink.CLASS_NAME}|all"
                };

                cs.Data = result;
                cs.CacheDependency = CacheHelper.GetCacheDependency(cacheDependencies);
            }
        }

        return result;
    }
}
1 votesVote for this answer Mark as a Correct answer

Petline developer answered on May 14, 2019 19:38

Thanks everyone for replying back! Very much appreciated.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.