#Rendering Main Navigation

1 messages Β· Page 1 of 1 (latest)

zinc marsh
#

Hi,

I am trying to render my main navigation on the frontend, I have my code in a partial and can get the links that are under the "Home" node.

I need to get any child pages of the child page under the home node.

I have this so far;

`@inherits Umbraco.Web.Mvc.UmbracoViewPage

@{
var selection = Umbraco.ContentAtRoot().FirstOrDefault()
.Descendants()
.Where(x => x.IsVisible());

}

<!-- NAVIGATION -->
<a class="menuopen"></a>
<nav>

<ul id="menu-main-menu" class="menu">
    @foreach (var item in selection)
    {
        <li>
            <a href="@item.Url" title="@item.Name">@item.Name</a>
        </li>
    }
</ul>

`</nav>
<a class="button" href="https://portal.principle-networks.com/" target="_blank" rel="nofollow noreferrer"><span>Portal Login</span></a>``

My content node structure looks like this https://prnt.sc/0um2Pv97wvHM

I've changed the children method to descendants and that's just listing ALL links as a long list.

This is what I am trying to achieve with the menu: https://prnt.sc/xwtL7-3r5k2R

Lightshot

Captured with Lightshot

Lightshot

Captured with Lightshot

reef jackal
#

If you're looping through the 'Children' of Home, then in your foreach loop, each Item should then expose it's Children recursively. Etc etc

zinc marsh
reef jackal
#

Yes sorry that is what I mean, so in your foreach loop in your example. Something similar to this should work

    <ul id="menu-main-menu" class="menu">
        @foreach (var item in selection)
        {
            <li>
                <a href="@item.Url" title="@item.Name">@item.Name</a>

                @if(item.Children().Any())
                {
                  <ul class="submenu">
                    foreach(var subitem in item.Children())
                    {
                      <li>
                        <a href="@subitem.Url" title="@subitem.Name">@subitem.Name</a>
                      </li>
                    }
                  </ul>
                }
            </li>
        }
    </ul>
#

(you may wish to handle that differently but item.Children() should give you the 'childrens children' of your home node

#

If I've understood your question correctly πŸ™‚

zinc marsh
#

Yeah, that makes sense @reef jackal but it throws this error;

error CS0103: The name 'subitem' does not exist in the current context'

reef jackal
#

You're quite right, I'd forgotten the 'var' in the second foreach. I've corrected that, that is more of an example though to give you an idea

zinc marsh
#

So the first foreach looks for the children nodes under the home node and then the 2nd loop looks for any children of the child

reef jackal
#

That's correct yes, and the second loop will only happen if there are any children to loop through πŸ™‚

zinc marsh
#

Ah, now the link that has children links, that is not showing at all on the frontend. but the other links are.

#

Now throwing an error here;

var selection = Umbraco.ContentAtRoot().FirstOrDefault().Children().Where(x => x.IsVisible());

System.NullReferenceException: 'Object reference not set to an instance of an object.'

reef jackal
#

All your doc types for your pages should inherit from IPublishedContent (built in to Umbraco), it's this that gives them the methods to access children etc

You can try the following, of course, the html markup, classes etc would need to be amended for your project I've just added some examples in here (for example the css class 'subitem')

<ul>
    @foreach (var item in selection)
    {
        <li>
            <a href="@item.Url" title="@item.Name">@item.Name</a>

            @if (item.Children().Any())
            {
                <ul class="submenu">
                    @foreach(var subitem in item.Children())
                    {
                        <li>
                            <a href="@subitem.Url" title="@subitem.Name">@subitem.Name</a>
                        </li>
                    }
                </ul>
            }
        </li>
    }
</ul>

Might also depend what version of Umbraco you're using. Either way, the .Children() method of your items in your loop should output what you need πŸ™‚

zinc marsh
#

Umbraco 8

reef jackal
#

Should be ok then

#

Sorry I missed your last message regarding the new error, I'm not sure what would be null in that instance, might be worth sticking a breakpoint on and finding out what is null - that looks ok as far as I can see

zinc marsh
reef jackal
#

Ah that definitely seems unrelated to any of the code above. Probably needs a restart, you can check the log files

zinc marsh
#

Where would I find the log file on my local machine?

reef jackal
#

Off the top of my head, I think it should be within the project directory, App_Data > Temp > Logs

#

Something like that

zinc marsh
#

Yes, found it, rebuilt the solution after cleaning it, ran it again and it's worked. I just need to build my html around the menu now πŸ™‚

reef jackal
#

Awesome, glad I could help. Good luck with the project

zinc marsh
#

Thank you, On the top LI element i Need to check if it has children pages and then append a class to it.

I've done the following;

<li class="@if(item.Children().Any()){ menu-item-has-children }">

System.Web.HttpCompileException: 'D:\sites\PrincipleNetworks.Web\Views\Partials\navigation.cshtml(13): error CS1002: ; expected'

reef jackal
#
            {
                var hasChildren = item.Children.Any();

                <li class="@(hasChildren == true ? "someClass" : null)">

You could do something like that (I've made 'hasChildren' a variable so that it's a little bit easier to read)

#

So if there are children, it will add 'someClass' if not, the class attribute will be empty

zinc marsh
#

Bizarre - i don't see anything wrong with the code but it keeps throwing

System.Web.HttpCompileException: 'D:\sites\PrincipleNetworks.Web\Views\Partials\navigation.cshtml(5): error CS1002: ; expected'

reef jackal
#

What is on line 5? It wants a semicolon (;) at the end of something

zinc marsh
#

fixed it now. πŸ˜„

reef jackal
#

πŸ‘

zinc marsh
#

Phew, I think that calls for lunch time - get away from the screen and come back refocused. πŸ™‚

tranquil mango
#

If you wanted something to support how ever many levels you have.. then if instead of using the navigation snippet to create a partial.. use the sitemap snippet.. that has a recursive traverse pattern.

The following is from v12, but think the partial snippet also exists in v8 as a starting point.

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models.PublishedContent
@using Umbraco.Cms.Core.Routing
@using Umbraco.Extensions

@inject IPublishedValueFallback PublishedValueFallback
@inject IPublishedUrlProvider PublishedUrlProvider
@*
    This snippet makes a list of links of all visible pages of the site, as nested unordered HTML lists.

    How it works:
    - It uses a local method called Traverse() to select and display the markup and links.
*@

@{ var selection = Model.Root(); }

<div class="sitemap">
    @* Render the sitemap by passing the root node to the traverse method, below *@
    @{ Traverse(selection); }
</div>

@* Helper method to traverse through all descendants *@
@{
    void Traverse(IPublishedContent? node)
    {
        //Update the level to reflect how deep you want the sitemap to go
        const int maxLevelForSitemap = 4;

        @* Select visible children *@
        var selection = node?.Children.Where(x => x.IsVisible(PublishedValueFallback) && x.Level <= maxLevelForSitemap).ToArray();

        @* If any items are returned, render a list *@
        if (selection?.Length > 0)
        {
            <ul>
                @foreach (var item in selection)
                {
                    <li class="[email protected]">
                        <a href="@item.Url(PublishedUrlProvider)">@item.Name</a>

                        @* Run the traverse method again for any child pages *@
                        @{ Traverse(item); }
                    </li>
                }
            </ul>
        }
    }
}