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>
}
}
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).
@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.
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"));
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>
}
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.
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?
Thanks!
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
This little helper function will do the trick ;)
And you can then use it like:
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.
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?
I hadn't thought about that, but yes. Perhaps I'll try making a pull request later today ;)
Wow great extension methods! I need something similar, but instead of
I need
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
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
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
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!
Looks like it was added by Stephan in "the big refactor" so it's also included in v6.2.0!
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:
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:
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:
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:
So the previous and next button now go to the correct node because it's also fetching the news items sorted by date.
Jeroen
is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.