Create a Branch Navigation Rendering

It’s an older style of navigation, but branch navigation still shows up in really big websites such as those found in higher education or health care.

Let’s look at an example of what we’re expecting:

Prerequisites

Make sure you’ve installed the NuGet package, built and deployed your Sitecore project.

Make sure Items in your content tree inherit from “Page” and “Navigation Title” as described here.

For instant gratification, make sure you’ve Published after the above changes.

The Controller

As with Breadcrumbs, we’ll use a Controller Rendering.


using System.Web.Mvc; 
using Constellation.Feature.Navigation.Models; 
using Constellation.Feature.Navigation.Repositories; 
using Sitecore.Data.Items; 
using Sitecore.Mvc.Presentation; 
namespace Website.Areas.ExampleSite.Controllers.Navigation 
{
     public class ExampleBranchNavigationController : Controller
     {
         public ExampleBranchNavigationController(IBranchNavigationRepository repository)
         {
                     this.Repository = repository;
         }

         public IBranchNavigationRepository Repository { get; set; }

         public ActionResult Index()
         {
              BranchNode model = Repository.GetNavigation(RenderingContext.Current.PageContext.Item);
              string view = GetViewName();
              return View(view, model);
         }

         protected string GetViewName()
         {
              return "~/Areas/ExampleSite/Views/Navigation/ExampleBranchNavigation.cshtml";
         }
     }
 }

After using Dependency Injection to get the IBranchNavigationRepository, we simply pass the Repository the Context Item to retrieve a tree of BranchNode objects that can be walked by the View.

The Repository here will look at the Context Item and crawl up the tree looking for an Item that implements Landing Page. This Item becomes the “root” of the navigation. From there, child Branch Nodes are appended and expanded as follows:

  • Children of the Landing Page are included.
  • The Child of the Landing Page that is an Ancestor of the Context Item is marked “active”
  • The Child of the Landing Page that is an Ancestor of the Context Item will have its immediate “Page” children included.
  • Any of these “Grandchild” Items that are Ancestors of the Context Item will similarly be marked Active and expanded until the Context Item is reached.
  • The Context Item will be included and marked “Active.” Its immediate children will be included.

The Model

The view will receive a single BranchNode object instance. That object offers the following details about the Page Item it represents:

  • ID The ID of the Item represented by this instance
  • DisplayName The DisplayName value of the Item
  • Url The URL of the Item as generated by the Context LinkManager
  • NavigationTitle The value of the Navigation Title field, which should be inherited by this Item.
  • GetBestLinkText() Returns the first non-empty value of NavigationTitle or DisplayName.

Additionally, the Model offers properties that tell the developer about its position in the tree:

  • Children A collection of BranchNode Items that are the immediate “Page” children of the Item
  • IsActive True if the Item passes the “Ancestor-or-self” XPath test.

The View

Chances are the HTML for this rendering is going to be specific to your needs, and will likely only support a known number of descending layers. Here’s an example:

@model Constellation.Feature.Navigation.Models.BranchNode
<div>
<h4>
<a href="@Model.Url">@Model.GetBestLinkText()</a>
</h4>
<ul class="nav flex-column">
@foreach (var node in Model.Children)
{
<li class="nav-item">
@if (node.IsActive)
{
<a class="nav-link active" href="@node.Url">@node.GetBestLinkText()</a>
if (node.Children?.Count > 0)
{
<ul class="nav flex-column">
@foreach (var subnode in node.Children)
{
<li class="nav-item">
@if (subnode.IsActive)
{
<a class="nav-link active" href="@subnode.Url">@subnode.GetBestLinkText()</a>
}
else
{
<a class="nav-link" href="@subnode.Url">@subnode.GetBestLinkText()</a>
}
</li>
}
</ul>
}
}
else
{
<a class="nav-link" href="@node.Url">@node.GetBestLinkText()</a>
}
</li>
}
</ul>
</div>

The “root” node of the branch is outside the loop, it’s children comprise the outer loop and its grandchildren the inner loop. Our example is based on Bootstrap 4.x navigation.