Endless scrolling based on a simple HTML pager
We had a little brainstorm today at work at how endless scrolling could be best implemented utilizing progressive enhancement. Here's my idea and a proof of concept. And a good example of progressive enhancement in pure form, if I may say so.
The concept
When I think of endless scrolling, I see it as just another form of paging. Any content asynchronously loaded when scrolling down is in fact the same you would have seen when an ordinary pager was implemented, clicking on a link "next". In practice, you don't see the page change, the content is just loaded below the content already there.
So what you need is this:
- A way of detecting whether the user is near the end of the page
- Then determine what the link to the next page is
- Load the content of that url
- Select only the items from that content and inject those items below the items already there
- Make sure the next time the user reaches the end of the page, the next page according to that content is loaded, unless there are no more pages left
1. Detecting the end of the page
This is done by comparing the difference of the document's height to the window's height, subtracting the window's scrollTop
(how far you scrolled down) and seeing if that crosses some hard coded threshold
.
#!javascript
if($(document).height() - $(window).height() <= $(window).scrollTop() + threshold) {
// load the next page
}
2. Determine what the link to the next page is
This is simple. You know where the pager links are (typically in some ul
), and the HTML spec provides a rel
attribute which can be used to define a relationship between the current page and the page linked to. In this case, next
is the right value to use.
So, the next link typically is the one within the pager, having a rel
attribute set to next
:
#!html4
<a href="..." rel="next">Next page</a>
In the script, we'll need to check whether a next link is actually available. If not, the endless scrolling doesn't prove to be that endless after all.
#!javascript
var a = $('a[rel=next]', 'div.pager ul').first();
if(a.length) {
// get the content from the link's href attribute
}
3. Loading the content
This is probably the easiest step, however, we need to be aware that the user might still be scrolling while the content is loaded. So, we flag a variable to make sure no second attempt at loading the next page is done while we're still loading the next page:
#!javascript
var loading = false;
if($(document).height() - $(window).height() <= $(window).scrollTop() + threshold) {
if(!loading) {
loading = true
$.get(page, function(data) {
// inject the data here
loading = false;
});
}
}
4. Select and inject the loaded items
Within the callback used to display the content, we can load the data into jQuery by passing that data to the jQuery constructor. Let's just assume the request will never fail, and we don't need to handle errors here, for the sake of the example. Using jQuery, we can use a selector to select the elements from the loaded content, and append them to the container
#!javascript
$.get(page, function(data) {
var dom = $(data);
var items =dom.find('.items');
container.append(items);
loading = false;
});
5. Prepare for the next time the user reaches the end
In my opinion, it's easiest to change the current DOM
in such a way that your subsequent pages load exactly the same way as the first one. This makes the plugin stateless, which is always easy to debug, and typically better pluggable.
Since we base the loading of our 'next' URL on the pager, we simply replace the pager with the one loaded in the asynchronous request.
#!javascript
$('.pager', container).replaceWith(dom.find('.pager'));
This way, the next time the user reaches the end of the page, the new pager is used to find the next page. Easy as pie.
Tuning the bits and pieces
Adding some code to make the selectors variable and hiding the pager whenever the plugin is activated, leaves you with a very usable version of an endless scrolling plugin, without you having ever to talk to a backend developer about it. How's that?
The proof
I whipped up the implementation of endless scrolling based on a HTML pager, putting it all together. The page is generated using some simple PHP code to show some random items over a few pages. View the HTML source if you don't know PHP; I provided a link to the PHP source as well, just to make sure the concept is clear. If you're not planning on reading the PHP, I'll tell you in advance that there are 10 5 pages in the example of 6 12 items per page, ending the scrolling at 66 items.
One gaping hole
Of course, this is just a proof of concept and there is at least one hole to plug. This version doesn't handle people entering the site at a page higher than the initial one. This means that, in fact, you should inject the content that is not yet loading above the initial content, by determining the prev
link from the pager.
I'll leave this to your imagination ;)
Happy scrolling :)