Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Nathan Woulfe 447 posts 1665 karma points MVP 5x hq c-trib
    Feb 20, 2012 @ 07:23
    Nathan Woulfe
    0

    Check if ancestor of current node

    Not sure if the post topic really explains what I'm trying to achieve - just exploring the possibilities of Razor, and trying to build out a simple site navigation. 

    I want it to work as below - if a page is selected at level 1, show its children. If a page is selected of those children, show that nodes' children.

    Level 1 page
    Level 1 page
    Level 1 page (the first page selected - show its children)
    --- Level 2 page
    --- Level 2 page 
    --- Level 2 page (the second page selected -show its children)
    ------ Level 3 page
    ------ Level 3 page
    --- Level 2 page 
    Level 1 page
    Level 1 page
    Level 1 page
    Level 1 page
    Level 1 page

    My current attempt is below - it works to build out the lists, but shows the entire nav tree - it should only show child nodes when the parent is selected. I guess what I need to do is build the nested lists, and as I add each item, check if it is an ancestor of the current page. 

    This would be ideal (item being the nav item being created, page the current page being served):

    item.IsAncestorOrSelf(page)

    My code (it's very much a rough run, surely someone can show me a much more robust way of achieving the same):

    @inherits RenderViewPage
    @using Umbraco.Cms.Web;
    @{
        var channel = DynamicModel;
        var page = DynamicModel;
    
        while (channel.Parent.ContentType.Alias != "homePage")
        {
            channel = channel.Parent;
        }
    }
    
    <ul>
        @foreach (var item in channel.Children) {
            var childName = item.Name ?? "(No name yet)";
            <li class="@(@page.Url == @item.Url ? "selected" : "")"><a href="@item.Url">@childName</a>
            @if (item.Children != null) {
                <ul>
                @foreach (var itemChild in item.Children) {
                var itemChildName = itemChild.Name;
                    <li class="@(@page.Url == @itemChild.Url ? "selected" : "")"><a href="@itemChild.Url">@itemChildName</a>
                    @if (itemChild.Children != null) {
                        <ul>
                        @foreach (var itemChildChild in itemChild.Children) {
                            var itemChildChildName = itemChildChild.Name;
                            <li class="@(@page.Url == @itemChildChild.Url ? "selected" : "")"><a href="@itemChildChild.Url">@itemChildChildName</a></li>
                        }
                        </ul>
                    }
                    </li>
                }
                </ul>
            }
            </li>
        }
    </ul>
    

     

  • Rodion Novoselov 694 posts 859 karma points
    Feb 20, 2012 @ 07:55
    Rodion Novoselov
    1

    Hi. There's really a method called "IsAncestorOrSelf" (You can refer to the umbraco razor cheetsheet: http://our.umbraco.org/projects/developer-tools/razor-dynamicnode-cheat-sheet). In fact I'm not sure about its performance in case of large count of nodes since it's implemented via iterating through all descendants of the node in question. If you face performance problems with that inbuilt implementation you can fall back to simply using the "Path" property that returns the IDs of all ancestors and the ID of the node itself separated by a comma:

    var isAncestorOrSelf = page.Path.Split(",").Contains(item.Id);

     

  • Nathan Woulfe 447 posts 1665 karma points MVP 5x hq c-trib
    Feb 21, 2012 @ 02:12
    Nathan Woulfe
    0

    Ha, there you go... I think I'm still missing something though.

    Using the example from part 7 of the Razor features walkthrough, I throw errors:

    <ul>
    @foreach(var item in channel.Children)
    {
        <li style="color:@item.IsEven("red","blue")">@item.Name</li>
    }
    </ul>

    Where channel is the same variable as my first example (ie contains the ancestor nodes of the current node, excluding the root node).

    Throws:

    Could not finding matching Signature for 'IsEven' with 2 parameters. Did you mean to call one of these?

     I'm on v5, if that makes a difference (I'm starting to think it might).

  • Alexey Badyl 33 posts 205 karma points
    Nov 04, 2014 @ 20:01
    Alexey Badyl
    0

    Hi, I recommend not use IsAncestor at all.

    This method work well when you have small content tree or if result of your razor will be cached by OurputCache properly. Otherwise when tree very big IsAncestor lead to High CPU and Memory issue.

    In our case we used it to build Main Navigation. By some reason this menu wasn't cached and IsAncestor  load full content tree per each user request.

    As result load test (Umbraco 6.1.6) show us that 30 concurent user kill our website, because memory grow from 800 MB to 4 GB, as result .net run GC  more offen with max CPU utilizaition => performance issue.

    To avoid performance issue use solution in first comment or use output cache. 

  • Peter S 169 posts 587 karma points
    Feb 13, 2015 @ 14:11
    Peter S
    0

    Using the snippet mentioned above will return true if you check for ID 10 when f.ex. node id 100 is in the chain, or 2010. Right? You'd need to iterate the strings in the array and see if they really match. I'd use something like this instead:

    public static bool IsAncestor(string path, int currentNode)
    {
    string[] nodes = path.Split(',');
    bool isAncestor = false;

    foreach (string node in nodes)
    {
     
    if (node.Trim() == currentNode.ToString())
     {
       isAncestor = true;
       break;
     }
    }

    return isAncestor;
    }
Please Sign in or register to post replies

Write your reply to:

Draft