Copied to clipboard

Flag this post as spam?

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


  • Jeavon Leopold 3074 posts 13631 karma points MVP 11x admin c-trib
    Dec 12, 2013 @ 11:21
    Jeavon Leopold
    1

    Filtered Next() and Previous() - v7 UmbracoHelper/MVC

    Ok, so I want to use the Next() and Previous() methods but I need them to be filtered as I want to skip nodes that are hidden, I've managed this but not in a nice way. I would love some suggestions on any improvement and do people think that maybe Next() and Previous() should have an overload method for a lambda expression?

    @{
        var siblingsCollection = Model.Content.AncestorOrSelf("CaseStudies").Children(x => x.IsVisible());
        var currentNodeIndex = siblingsCollection.FindIndex(x => x.Id == this.Model.Content.Id);
        var nextNode = siblingsCollection.ElementAtOrDefault(currentNodeIndex + 1);
        var previousNode = siblingsCollection.ElementAtOrDefault(currentNodeIndex - 1);
    
        if (nextNode != null)
        {
            <a href="@nextNode.Url" class="next">Next case study //</a>
        }
    
        if (previousNode != null)
        {
            <a href="@previousNode.Url" class="prev">Previous case study //</a>
        }
    }
    

    Thanks!

  • Peter Duncanson 430 posts 1360 karma points c-trib
    Dec 12, 2013 @ 13:59
    Peter Duncanson
    0

    Hi Jeavon,

    Well, it seems to do the job. What is it about it you don't like? I was going to suggest maybe using siblings but its not part of the IPublishContent object sadly plus the way you have your AncestorsOrSelf call would allow for date nested folders for instance so would be a better way to do it anyway. Its a little long winded for what seems like a simply thing to do but it does the job, I'd be happy with it.

    An overload on the Next/Previous would be good or a list of all all next and previous (aka preceding-sibling and following-sibling in xpath).

    Pete

  • Anders Bjerner 487 posts 2989 karma points MVP 8x admin c-trib
    Dec 12, 2013 @ 14:04
    Anders Bjerner
    2

    This little helper function will do the trick ;)

    @functions {
        public IPublishedContent Next(IPublishedContent current, Func<IPublishedContent, bool> func) {
            IPublishedContent next = current.Next();
            while (next != null) {
                if (func(next)) return next;
                next = next.Next();
            }
            return null;
        }
    }
    

    And you can then use it like:

    var next = Next(Model.Content, x => x.IsVisible());
    

    However since this might be something that is going to be used in several files, it would probably be best to turn it into an extension method rather than a helper function.

  • Jeavon Leopold 3074 posts 13631 karma points MVP 11x admin c-trib
    Dec 12, 2013 @ 14:22
    Jeavon Leopold
    0

    Really nice! As an extension method on IPublishedCotnent it's my lamda overload method! I think it should be in core anyway, don't you?

  • Anders Bjerner 487 posts 2989 karma points MVP 8x admin c-trib
    Dec 12, 2013 @ 14:25
    Anders Bjerner
    100

    I hadn't thought about that, but yes. Perhaps I'll try making a pull request later today ;)

  • Jeroen Breuer 4908 posts 12265 karma points MVP 5x admin c-trib
    Dec 18, 2013 @ 13:43
    Jeroen Breuer
    0

    Wow great extension methods! I need something similar, but instead of 

    .Children(x => x.IsVisible())

    I need

    .Children().OrderBy(x => x.GetPropertyValue<DateTime>("currentDate"))

    Can I also do that with your extension methods or do I still need to use Jeavon his first post example for this?

    Btw when I do .Children I can't do something like x => x.IsVisible() in it. Only () is allowed.

    Jeroen

  • Jeavon Leopold 3074 posts 13631 karma points MVP 11x admin c-trib
    Dec 18, 2013 @ 14:06
    Jeavon Leopold
    0

    That would be nice, but you could do a where first? e.g. Model.Content.AncestorOrSelf(1).Children().Where(x => x.IsVisible()).OrderBy(x => x.GetPropertyValue<DateTime>("currentDate"));

    Also Anders did make his first pull request with this! https://github.com/umbraco/Umbraco-CMS/pull/267

  • Jeroen Breuer 4908 posts 12265 karma points MVP 5x admin c-trib
    Dec 18, 2013 @ 14:12
    Jeroen Breuer
    0

    I know I can do the Where. I just wondered if I need to use the example from your first post or could use an extension method for this.

    Jeroen

  • Jeavon Leopold 3074 posts 13631 karma points MVP 11x admin c-trib
    Dec 18, 2013 @ 14:16
    Jeavon Leopold
    0

    Oooh yeah, I hadn't noticed, it's something new in v7, just tried in v6.1.6 and it's not there but v7, no problem!

  • Jeavon Leopold 3074 posts 13631 karma points MVP 11x admin c-trib
    Dec 18, 2013 @ 15:39
    Jeavon Leopold
    0

    Looks like it was added by Stephan in "the big refactor" so it's also included in v6.2.0!

  • Anders Bjerner 487 posts 2989 karma points MVP 8x admin c-trib
    Dec 18, 2013 @ 17:31
    Anders Bjerner
    2

    Hi Jeroen,

    I'm not totally sure what you're trying to do, but these helper functions might help you out in Umbraco 6.1.x:

    @functions {
        public IEnumerable<IPublishedContent> Children(IPublishedContent current, Func<IPublishedContent, bool> func) {
            return current.Children.Where(func);
        }
        public IEnumerable<IPublishedContent> Siblings(IPublishedContent current, Func<IPublishedContent, bool> func) {
            return current.Siblings().Where(func);
        }
    }
    

    Umbraco 7 has a Children method that takes a delegate/predicate as the second parameter, but not a Siblings method, so I'll try adding that to the core as well.

    Anyways - in Umbraco 6.1.x the helper methods could be used like this:

    foreach (var sibling in Siblings(Model.Content, x => x.DocumentTypeAlias == "Page").OrderBy(x => x.CreateDate)) {
        <p>@sibling.Name (@sibling.DocumentTypeAlias)</p>
    }
    
  • Jeroen Breuer 4908 posts 12265 karma points MVP 5x admin c-trib
    Dec 19, 2013 @ 09:52
    Jeroen Breuer
    0

    Here's how I'm currently doing it and I'll also try to explain why.

    This is the news overview controller which displays news items sorted by date:

    public class NewsOverviewController : BaseSurfaceController
    {
        [DonutOutputCache(Duration = 86400, Location = OutputCacheLocation.Server, VaryByCustom = "url;device")]
        public ActionResult NewsOverview()
        {
            var model = GetModel<NewsOverviewModel>();
            var newsItems = GetNewsItems();
            var pager = Umbraco.GetPager(6, newsItems.Count());
    
            //Only put the paged items in the list.
            model.NewsItems = newsItems.Skip((pager.CurrentPage - 1) * pager.ItemsPerPage).Take(pager.ItemsPerPage);
            model.Pager = pager;
    
            return CurrentTemplate(model);
        }
    
        public IEnumerable<NewsItem> GetNewsItems()
        {
            return
            (
                from n in CurrentPage.Children
                orderby n.GetPropertyValue<DateTime>("currentDate") descending
                select new NewsItem()
                {
                    Title = n.GetPropertyValue<string>("title"),
                    Category = n.GetPropertyValue<string>("categorie"),
                    Url = n.Url(),
                    Image = n.GetCroppedImage("image", 108, 81),
                    Date = n.GetPropertyValue<DateTime>("currentDate")
                }
            );
        }
    }

    This is how it looks on the website:

    Because it's sorted by date Nieuwsbericht 2 is on top. If I go to the details page of Nieuwsbericht 1 there is a previous and next button on that details page. In this case if I press previous it should go to Nieuwsbericht 2 and if I press next it should go to Nieuwsbericht 3. If I would us Model.Content.Next() it would go the next item as sorted in the Umbraco tree and not sorted by date. That's why I'm currently doing it like this in the news item controller:

    public class NewsItemController : BaseSurfaceController
    {
        [DonutOutputCache(Duration = 86400, Location = OutputCacheLocation.Server, VaryByCustom = "url;device")]
        public ActionResult NewsItem()
        {
            var model = GetModel<NewsItemModel>();
            var newsItems = GetNewsItems();
            var currentNodeIndex = newsItems.FindIndex(x => x.Id == CurrentPage.Id);
    
            model.NextNewsNode = newsItems.ElementAtOrDefault(currentNodeIndex + 1);
            model.PreviousNewsNode = newsItems.ElementAtOrDefault(currentNodeIndex - 1);
    
            return CurrentTemplate(model);
        }
    
        public IEnumerable<IPublishedContent> GetNewsItems()
        {
            var newsNode = Umbraco.TypedContent(CurrentPage.TopPage().GetPropertyValue<int>("selectNewsNode"));
    
            return
            (
                from n in newsNode.Children
                orderby n.GetPropertyValue<DateTime>("currentDate") descending
                select n
            );
        }
    }

    So the previous and next button now go to the correct node because it's also fetching the news items sorted by date.

    Jeroen

Please Sign in or register to post replies

Write your reply to:

Draft