4

I have a multilevel navigation control and I would like to add an active class and aria-expanded="true" to the <a> tag when one of the item's descendants' ID matches the Html.Sitecore().CurrentItem.ID so that the navigation will load pre-expanded based on wherever the user lands in the hierarchy of the site.

To demonstrate - if the current URL was /A/A2/A2.2

And if the navigation had a structure like this:

A
    A1
    A2
        A2.1
        A2.2
    A3
B
    B1
    B2
        B2.1
C
D
    D1
        D1.1
    D2

I'd like to have a simple check for each item rendered that would essentially be something like:

<a class="@{i.Axes.Descendants().Any(d => d.ID == Html.Sitecore().CurrentItem.ID) ? 'active' : '';}">A</a>

So the A section would start off expanded while B - D would start collapsed.

5

There's a method that does basically what jammykam initially suggests. It uses StartsWith but that really shouldn't ever matter when comparing long ids. It is Sitecore.Data.Items.ItemAxes.IsDescendantOf(Item item) which can be used as follows: currentItem.Axes.IsDescendantOf(i).

2
  • 1
    Ah nice! Too used to using the code with Indexes :D – jammykam Oct 3 '17 at 23:38
  • This is the cleanest and most "Sitecore" way to figure out active ancestors. (Item.Axes is a very old part of the API). Assuming you're using HTML caching for your navigation based on the Context item, you shouldn't see any performance issues with this call. – Sergeant Sitecore Oct 5 '17 at 13:51
4

The simplest option is to check if the Paths.LongID property of the current page item contains the menu item ID.

@Html.Sitecore().CurrentItem.Paths.LongID.Contains(i.ID.ToString())

This works because the LongID property contains a string representation of all parent item GUIDs and since the item GUIDs are unique you can rely on it only matching if they are descendants.

A couple of thoughts. Since you are adding additional properties to the markup for each menu item / site section, it will make it difficult to cache your menu components - you will have a lot of variations or have to cache per page. Personally, I would consider moving the logic into JavaScript and check the current page URL against the href property of the menu items. If you want to avoid a flicker whilst waiting for the document.ready event to fire then you can inline block the JS code in the menu component so it fires immediately. This will allow you to cache your menu component once for all pages.

Also be careful about using @Html.Sitecore().CurrentItem, it will return the datasource ID if one is set. Perhaps you meant to use Sitecore.Context.Item or @Model.PageItem in MVC world.

3

Instead of checking Axes.Descendants, create a list of Ancestors (or their IDs) of your current item.

Then check if your current item is on that list.

That will million times faster as you only create the set of "active" IDs once.

You can get the list of current item ancestors IDs from:

currentItem.Paths.LongID

Just use:

var ancestorsIds = currentItem.Item.Paths.LongID.Split(new char[]{'/'}, StringSplitOptions.RemoveEmptyEntries);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.