For a menu, determine if node has child elements

Stephen Herz asked on November 2, 2016 23:43

Using Kentico v9

I am trying to add a class attribute to my menu <li> tags only if they have child elements. I am using an ASCX transform and a regular Repeater web part. I am using DocumentMenuItemHideInNavigation = 0 in my WHERE condition to filter out certain content items. I then check for Eval("NodeHasChildren") in the transform but this returns true if that node has any content in the tree. However, I want to determine if the there are any children in the result set (filtered by my WHERE clause), not what is in the tree in the dashboard. Is there any way to do this?

Correct Answer

Brenden Kehren answered on November 3, 2016 00:54

This works inline in the transformation but it's probably best to create a custom transformation method and reference the method.

<script runat="server"> 
bool hasChildren;
protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    hasChildren = ValidationHelper.GetBoolean(CMS.DocumentEngine.DocumentHelper.GetDocuments("CMS.MenuItem").Path(Eval<string>("NodeAliasPath"), CMS.DocumentEngine.PathTypeEnum.Children).Where("DocumentMenuItemHideInNavigation = 0").Count > 0, false);
}

Keep in mind, this will run for every page that is being found so you'll want to be sure you set caching on the webpart for navigation so it isn't running each time the page loads or reloads.

2 votesVote for this answer Unmark Correct answer

Recent Answers


Anton Grekhovodov answered on November 3, 2016 17:53

To optimize performance, you can also use Basic Repeater + Query Data Source, where you can calculate children items

0 votesVote for this answer Mark as a Correct answer

Peter Mogilnitski answered on November 3, 2016 19:21

You might consider changing your repeater to CSS List Menu (it automatically hide menu items according to "Show in navigation"). All menu logic is solved in there. I strongly suggest you to use it. Take as example on "the corporate site" and see how the css list menu is done there.

If you still want to use your repeater do it with a custom query just use SQL with calculated column VisibleCHildrenCount for ex.:

WITH MenuQuery 
(NodeHasChildren, NodeID, NodeName,  NodeLevel, NodeOrder, DocumentName, DocumentMenuItemHideInNavigation, NodeParentID)
AS
(
-- default query for cms menu list with fewer columns
SELECT  
NodeHasChildren, NodeID, NodeName, NodeLevel, NodeOrder, DocumentName, DocumentMenuItemHideInNavigation, NodeParentID
FROM View_CONTENT_MenuItem_Joined 
WHERE [NodeSiteID] = 2 AND ((DocumentMenuItemHideInNavigation = 0) 
AND (MenuItemGroup <> 'footer' OR MenuItemGroup IS NULL)) 
AND ([Published] = 1  AND [NodeLevel] <= 2  AND [DocumentCulture] = 'en-US') 

)
SELECT VisibleCHildrenCount = 
    (SELECT COUNT(*) FROM MenuQuery q2 
    WHERE q2.[DocumentMenuItemHideInNavigation] =0 and q2.NodeParentID = q1.NodeID), *
FROM  MenuQuery q1
ORDER BY NodeLevel, NodeOrder, DocumentName
0 votesVote for this answer Mark as a Correct answer

Stephen Herz answered on November 17, 2016 01:25

I implemented Brendan's solution and that worked perfectly. I built it as a custom transformation method so it could be reused. I also made sure to cache the output for performance reasons.

0 votesVote for this answer Mark as a Correct answer

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