How to use Razor in Umbraco - Paging

Note: this post is over a year old, it's very likely completely outdated and should probably not be used as reference any more. You have been warned. :-)

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>&nbsp;</text>
}
else
{
<a href="@library.NiceUrl(currentId)?page=@i">@i</a><text>&nbsp;</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. :-)

Sebastiaan Janssen

Dutch guy living in (and loving) Copenhagen, working at Umbraco HQ. Lifehacker, skeptic, music lover, cyclist, developer.

 

14 comments on this article

Avatar for Nate Nate | February 17 2011 22:03
Nice stuff! Keep them coming!

Avatar for Lenni 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.

Avatar for Anthony Candaele 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

Avatar for Sebastiaan Janssen 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.

Avatar for Anthony Candaele 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

Avatar for Sebastiaan Janssen 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.

Avatar for Anthony Candaele Anthony Candaele | May 10 2011 16:14
Oh, then I'll be patient and wait 'till the end of the month :)

Avatar for Julius Bartkus 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

Avatar for Sebastiaan Janssen 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"]).

Avatar for Julius Bartkus 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;

Avatar for Barry 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!

Avatar for publicacc publicacc | October 18 2011 03:50
How to initilialize the paging object. Can you explain more detail? Thanks

Avatar for Trieu Hoang 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"

Avatar for Brendan Rice Brendan Rice | December 4 2011 21:35
Nice one mate will definatly be using this :)