Copied to clipboard

Flag this post as spam?

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


  • Simon Dingley 1474 posts 3431 karma points c-trib
    Sep 25, 2012 @ 12:38
    Simon Dingley
    0

    Filter Child Nodes using Contains and Exclusion List

    I would like to filter the Child nodes returned from a Where clause excluding all nodes that are in a list of excluded document types however I am still getting child nodes back regardless of the doctype being in the list of excluded doctypes.

    See below example:

    var excludedDoctypes = new[] { "BlogPost", "NewsArticle" };
    var childNodes = node.Children.Where("!excludedDoctypes.Contains(NodeTypeAlias)");

    Can I achieve what I'm asking for in this way and I'm missing something or is it just not possiblle?

    Thanks, Simon

  • Funka! 398 posts 661 karma points
    Sep 26, 2012 @ 18:46
    Funka!
    1

    I'm sure there may be a fancier way to pass in a filter statement (as a Func<INode,bool>) to the Descendants collection, but in the past, for simplicity, I have gotten away with the following:

    var excludedDoctypes = new[] { "BlogPost", "NewsArticle" };
    var childNodes = node.Children; // just grab em all and filter them out later
    foreach (var childNode in childNodes)
    {
      if (!excludedDoctypes.Contains(childNode.NodeTypeAlias))
      {
        // do your magic here
      }
    }

    Another trick I have used, when it's important for me to know for example the exact count of the nodes, is to use that same iteration logic but instead of "doing magic" where shown above, instead would build up a new List containing just the nodes I want. (And then, I can call .Count on this, iterate through it again as needed, etc.)

    Good luck!

  • Simon Dingley 1474 posts 3431 karma points c-trib
    Oct 01, 2012 @ 16:01
    Simon Dingley
    0

    Thanks, I was trying to avoid doing that if I could because I am potentially grabbing more nodes in the request than what I really need. That said I should perhaps I should just take the plunge and allow a few extra lines to creep in just to get the job done as the overhead may be minimal anyway. 

  • Funka! 398 posts 661 karma points
    Oct 01, 2012 @ 19:52
    Funka!
    0

    You raise a good point. It would be interesting to see "behind the scenes" profiling to see if there is any significant difference between passing in a filter clause to the Where method, ...or whether just looping the whole thing and deciding yourself. The only way really is for you to time it and see.

    Another idea to consider is to use the XPath filtering method. This would also be something interesting to time, and see how it compares to the aforementioned approach. Something like:

    var childNodes = Model.XPath(@"*[(name() != 'BlogPost') and (name() != 'NewsArticle')]");

    Good luck! And let us know what you end up with!

  • Dan Diplo 1554 posts 6205 karma points MVP 6x c-trib
    Oct 02, 2012 @ 15:26
    Dan Diplo
    1

    If you can change your "node" to be a DynamicNode then you can use "proper" strongly-typed LINQ statements like this:

        var excludedDoctypes = new[] { "BlogPost", "NewsArticle" };
        DynamicNode node = Model; // your start node
        var childNodes = node.ChildrenAsList.Where(x => !excludedDoctypes.Contains(x.NodeTypeAlias));
    
        foreach (dynamic item in childNodes)
        {
            <p>@item.Name @item.NodeTypeAlias</p>
        }
  • suzyb 474 posts 932 karma points
    Nov 06, 2012 @ 13:03
    suzyb
    0

    I am trying to use the code Funka posted but am getting an error.

    The error I'm getting is

    'string[]' has no applicable method named 'Contains' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

    And my code

    var excludedDoctypes = new[] { "Settings", "ErrorPages" };
    @foreach (var item in homeNode.Children.Where("Visible"))
    {
    if (!excludedDoctypes.Contains(item.NodeTypeAlias))
    {
    var selected = Array.IndexOf(Model.Path.Split(','), item.Id.ToString()) >= 0 ? " class=\"selected\"" : "";
    <[email protected](selected)>
    <a href="@item.Url">@item.Name</a>
    </li>
    }
    }

    As far as I can see my code is the same as that posted.  So why is it not working :(

  • suzyb 474 posts 932 karma points
    Nov 12, 2012 @ 10:55
    suzyb
    0

    I changed my approach and tried what Dan suggested. I made homeNode a DynamicNode and do this to select the children

    var childNodes = homeNode.ChildrenAsList.Where(x => !excludedDoctypes.Contains(x.NodeTypeAlias) && x.GetProperty("umbracoNaviHide").Value != "1");

     

  • Funka! 398 posts 661 karma points
    Nov 13, 2012 @ 03:52
    Funka!
    0

    Hi suzyb,

    I'm glad you were able to get something working. Not sure why the sample you took from my post 7 weeks ago did not work, I'm fairly certain I had copied that from a working installation. But since I don't recall right now where that was from, it's also possible I changed or forgot something that's causing you the problem? Based on the error message you're indicating, I wonder if simply casting the argument to the "Contains" extension method would work? For example:

    if(!excludedDoctypes.Contains(item.NodeTypeAlias.ToString()))

    Although, if what you have now is working for you, probably no reason to mess with a good thing. In terms of which is more "performant", my guess is they are both incredibly similar.

    Best of luck to you!

Please Sign in or register to post replies

Write your reply to:

Draft