How to use Razor in Umbraco - Paging
In my previous post I've shown the basics of using Razor. But I also wanted to find out what works better in XSLT versus in Razor. Luckily, my page needed paging. Paging is something relatively simple that requires a bit of logic, not something that is trivial to do in XSLT. In fact, every time I look at the faux-"for loop" required in XSLT to make it work, my head starts spinning.
Disclaimer: The Razor implementation is still very new and changing rapidly, some of this information might already be outdated.
Paging is also something that can be made really generic, making it nicely reusable for any page.
There is two parts to the paging solution, a normal C# class (but in the App_Code folder, so no compilation required!) that takes the amount of items and the items that should be displayed per page and then does some calculations based on the "page" querystring (come to think of it, I should've actually made that an input variable as well).
I admit that this is a bit verbose and I don't actually need some of these fields, but it's nice to have them in case I need to do something wild with them later.
using System;
using System.Web;
public class Paging
{
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public int PreviousPage { get; set; }
public int NextPage { get; set; }
public double TotalPages { get; set; }
public int Skip { get; set; }
public int Take { get; set; }
public static Paging GetPages(int itemCount, int itemsPerPage)
{
int page;
int.TryParse(HttpContext.Current.Request.QueryString["page"], out page);
if (page == 0) page = 1;
var pages = new Paging { ItemsPerPage = itemsPerPage, CurrentPage = page, PreviousPage = page - 1, NextPage = page + 1, TotalPages = Math.Ceiling(itemCount / (Double)itemsPerPage), Skip = (page*itemsPerPage) - itemsPerPage, Take = itemsPerPage };
return pages;
}
}
Then, I needed a really basic way to show the paging. I wanted just some links for the different pages and a "previous" and "next" link. Also, the "current" page shouldn't be clickable. So we bring out a Razor helper (also in the App_Code folder) that can be reused and potentially modified when needed.
@using umbraco;
@helper RenderPaging(Paging paging, int currentId) {
if (paging.CurrentPage > 1)
{
<a href="@library.NiceUrl(currentId)[email protected]">< Vorige</a>
}
for (var i = 1; i <= paging.TotalPages; i++)
{
if (paging.CurrentPage == i)
{
@i<text> </text>
}
else
{
<a href="@library.NiceUrl(currentId)?page=@i">@i</a><text> </text>
}
}
if (paging.CurrentPage < paging.TotalPages)
{
<a href="@library.NiceUrl(currentId)[email protected]">Volgende ></a>
}
}
That's all, so now in my overviewpage, I initilialize the paging object and select the records that I want to show for the current page. Note that Skip() and Take() have been added to my Linq query so that I only get the 10 articles that I want.
@{ var paging = Paging.GetPages(allArticles.Count(), 10);
var selectedArticles = allArticles.OrderByDescending(x => x.CreateDate).Skip(paging.Skip).Take(paging.Take).ToList(); }
<div class="articleList">
<ul>
@foreach(var article in selectedArticles) {
<li>@article.NodeName</li>
}
</ul>
And finally, to render the paging, it's a matter of calling the helper, note that the namespace is once again the name of the .cshtml file (as in the functions in the previous post).
<div class="paging">
@PagingTemplate.RenderPaging(paging, Current.Id)
</div>
There you go, from 100+ lines of unreadable XSLT to about 60 lines of nice, clean and easily reusable paging in Razor. What's not to love?
Ps. I still love XSLT, really I do. :-)
14 comments on this article
Nate | February 17 2011 22:03
Nice stuff! Keep them coming!
Lenni | March 20 2011 18:51
Great work, I combined it with the Examine search example from joeriks blog and now I've got a razor search engine with paging.
Anthony Candaele | May 10 2011 11:41
Hi Sebastiaan,
Thanks for this article on creating a pager with Razor. That's just what I need for my new portfolio page. I need a pager that pages a pages with projects.
There is one thing that is not really clear to me. In your article, you mention the 'overviewpage'. Is this an Umbraco Template, or is it a Razor script file?
Greetings,
Anthony
Sebastiaan Janssen | May 10 2011 12:20
With overview page I mean the page that the paging is on (which is an Umbraco template, with a Razor script file, hehe).
FYI, there's a paging example (and other examples) in Umbraco 4.7.1, click on the arrow down next to the "Insert Inline Razor" macro button in Umbraco's template editor.
Anthony Candaele | May 10 2011 14:18
Oh, and where can I find this Umbraco 4.7.1 version? I checked Codeplex but there I only find Umbraco 4.7.0
Sebastiaan Janssen | May 10 2011 15:18
Sorry, meant 4.7 :-)
Personally, I'm running a self-compiled build off of the recent source code, which I'm calling 4.7.1. Looks like it should be out by the end of the month though.
Anthony Candaele | May 10 2011 16:14
Oh, then I'll be patient and wait 'till the end of the month :)
Julius Bartkus | August 9 2011 10:46
There is no need for currentId in
@helper RenderPaging(Paging paging, int currentId) {
because paging holds CurrentPage value
Sebastiaan Janssen | August 9 2011 10:49
I could've named that variable better, but this is not the CurrentPage as you know it from XSLT. It's the curent page number (which is set as: HttpContext.Current.Request.QueryString["page"]).
Julius Bartkus | August 9 2011 14:13
ah, sure, you are right...
one more thing could be improved is checking whether the user not trying to enter exceeding page or lower than 1
in
public static Paging GetPages(
...
double totalPages = Math.Ceiling(itemCount/(Double) itemsPerPage);
if (page < 1) page = 1;
if (page > totalPages) page = (int)totalPages;
Barry | September 22 2011 18:04
I'm a big fan of this paging method Sebatiaan, thanks for sharing. I was wondering if ytou evert looking into integrating it with some jQuery - so that it only shows e.g. 10 items, and when you click on a link near the 'edge' the paging bar on the subsequent page moves to show the next set.
Not great at jQuery etc so any pointers, or code you can share that accomplishes this, would be much appreciated!
publicacc | October 18 2011 03:50
How to initilialize the paging object. Can you explain more detail? Thanks
Trieu Hoang | October 18 2011 03:57
I do follow your instruction, I get below error. Can you help me?
"Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type"
Brendan Rice | December 4 2011 21:35
Nice one mate will definatly be using this :)