February
18th, 2008
Eliminate paging results by using JavaScript (ala DZone)
I noticed that DZone had a really cool UI for a list of user submitted links. DZone is similar to Digg but geared more towards programmers. The premise is that a small subset of links are populated when the page loads. Once the user begins to scroll and nears the bottom of the list it automatically populates more stories to the end. This is a great alternative to having numerous pages that the user has to click through. You can also view a working example.
The tools
I decided to use the prototype.js library because I didn’t want to spend more than a couple hours on the scripting portion of this. I also needed some good sample data and decided to go with Digg’s API to get a list of the latest 100 photos. On the backend I used PHP but you can swap that out with something else if you’d like.
The photos
First let’s get the photos from Digg. I used a simple PHP curl request to connect to their web service.
$ch = curl_init('http://services.digg.com/galleryphotos?count=100&type=json&appkey=test');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP');
$full = json_decode(curl_exec($ch), true);
$stories = json_encode($full['photos']);
I went ahead and decoded the response to a PHP array and stored the photos key to a variable named $stories. I re-encoded that to a JSON string because we’re going to pass that into our JavaScript constructor.
The JavaScript
We’re going to utilize a few prototype.js functions to make this clean and fast.
- Class.create
- Element.insert
- Element.observe
- Element.stopObserving
- Element.getDimensions
- document.viewport.getScrollOffsets
We’ll start by defining some simple CSS.
.epiItem{
height:100px;
background-color:#eee;
border-bottom:#ccc dotted 1px;
}
Let’s additionally set up a div which we’ll use to populate the photos. We’ll also need to include the prototype.js library (change the path as needed).
<script src="/js/prototype.js"></script>
Now we’re ready for the javascript. Here’s the class we’ll use to handle everything.
var EpiList = Class.create(
{
displayItem: function(item)
{
$('epiList').insert('
'+item.title+'
', {position:'bottom'});
this.item++;
},
onScroll: function()
{
var previousScroll = this.scroll['top'];
this.scroll = document.viewport.getScrollOffsets();
if(this.scroll['top'] > previousScroll)
{
if((this.scroll['top'] / this.viewport['height']) > .60)
{
if(this.item < this.items.length)
{
this.displayItem(this.items[this.item]);
this.reset();
}
else
{
this.stopObserving();
}
}
}
},
observe: function()
{
Event.observe(document, 'scroll', this.onScroll.bind(this));
Event.observe(window, 'resize', this.reset.bind(this));
},
reset: function()
{
this.scroll = document.viewport.getScrollOffsets();
this.viewport = $('content').getDimensions();
},
stopObserving: function()
{
Event.stopObserving(document, 'scroll', this.onScroll.bind(this));
Event.stopObserving(window, 'resize', this.reset.bind(this));
},
initialize: function(items, display)
{
this.reset();
this.item = 0;
this.increment = 3;
this.items = items;
this.display = display;
for(i=0; i
{
this.displayItem(this.items[i]);
}
this.observe();
}
}
);
new EpiList(, 10);
Notice the PHP code at the very end? That’s the JSON encoded data that we got using the PHP code above.
How it works
We create an instance of the EpiList class which fires off the constructor initialize(items, display). We pass in the JSON string as the list of items which we specified as 100 photos. We also pass in 10 as the default number of photos to prepopulate. The last line of the constructor is a call to the observe() method. This sets up event handlers for when the user scrolls or resizes the window. The main method is the onScroll() method. This is what checks to see if the scrollbar is at least 65% of the way near the end. If it is then we append another photo to the bottom of the div. This keeps the page growing and the user is pretty much unaffected - a win win.
The benefits
This approach has many benefits including a great user experience and decreased bandwidth/server load…if implemented correctly of course.
Disclaimer
This is just a proof of concept that is completely unoptimized.

February 18th, 2008 at 6:00 pm
I think part of the point of paging is so the user doesn’t have an unsurmountable number of records to view at one time. With this method you will continue to increase the number of records on the page until it becomes too much for the user. At that point it would be hard for the user to find a specific record in the set - especially if they leave your page and then want to come back and find a record. And what happens when I find something good that’s number 250 in the list, how do I share that with a friend? With paging I can send a link to the page, or at least tell them which page it’s on. Seems cool but not practical.
February 18th, 2008 at 7:55 pm
That’s a good point. I do still think that there are good applications for it though. Think about Digg’s “upcoming” section. Links get added so frequently that the pages don’t really help bookmark any specific entry. This doesn’t replace paging…but provides an alternative.
Something additional to consider is that users are familiar with paged results. I like this solution because it feels pretty seamless…but there’s value in interfaces which users are familiar with.
February 19th, 2008 at 9:18 am
I implemented this using jQuery…never got time to blog it though :)
but the points that kevin has mentioned are very good. One way to avoid this could be to add some sort of sticky link that would take you back to the previously loaded subset.
As for sending ‘link’ to your friend..well this example just has images..but if your ’s (or whatever you’d use) had html links then used could just send those links.
but a good example nonetheless…
February 19th, 2008 at 9:48 am
@bhaarat
I was originally going to do this using YUI. It’s on my list of things to learn but I knew I could whip it up real quick with prototype.js. If you have a working example using jQuery then link it here…I’d like to see it.
February 19th, 2008 at 10:10 am
Also this makes entries not accessible by web crawlers.
February 19th, 2008 at 10:14 am
@Anton, also a good point. Ajax/dHTML in general is not very web crawler friendly. At the moment anyways.
If SEO is important then I think it’s still doable using this method. You would have to make sure that the link structure on the site (aside from or in addition to) a page that includes Ajax/dHTML ensures that search engines can reach all parts of the site.
February 20th, 2008 at 6:47 am
Google use something similar in their Feed Reader. Makes scrolling through 100s of Feed-Items a charm.
So the technique surely has its applications. Maybe not so for ordered data sets as Kevin pointed out.
I too would like to see the jquery implementation of this.
February 24th, 2008 at 4:04 pm
I have a jquery implementation on my blog: Aurgasm. I’m also in the final stages of releasing a Wordpress plugin for Infinite Scroll that captures all this functionality.
I think I’ll add in some permalink functionality now, since there is definite demand for it.
btw- this comment captcha is infuriating.