Alex Kehayias's Blog

  • Archive
  • RSS

Infinite Scroll with Django

Twitter style infinite scroll using Django as your backend is actually pretty simple. I did it for the TimeoutDebate archive page. You can break it down into these simple steps:

  1. Scrolling past a certain point triggers a jquery ajax event
  2. Django responds with a json object
  3. Insert the new data into the document, reload the scroll handler

That’s really not much different than any other ajax type of interaction. There’s no black magic (there rarely is) although I did need to look up how to actually capture this event. I found a good article about infinite scroll with django here, but ended up rolling my own backend handler. 

This is how you capture the event of scrolling past a certain point (via Palewire, the article I mentioned):

$(document).ready(function(){     
   $(window).bind('scroll', loadOnScroll);
});

// Scroll globals
var pageNum = 1; // The latest page loaded
var hasNextPage = true; // Indicates whether to expect another page after this one

// loadOnScroll handler
var loadOnScroll = function() {
   // If the current scroll position is past out cutoff point...
    if ($(window).scrollTop() > $(document).height() - ($(window).height()*2)) {
        // temporarily unhook the scroll event watcher so we don't call a bunch of times in a row
        $(window).unbind(); 
        // execute the load function below that will visit the JSON feed and stuff data into the HTML
        loadItems();
    }
};

var loadItems = function() {
    // If the next page doesn't exist, just quit now 
    if (hasNextPage === false) {
        return false
    }
    // Update the page number
    pageNum = pageNum + 1;
    // Configure the url we're about to hit
    $.ajax({
        url: '',
        data: {page_number: pageNum},
        dataType: 'json',
        success: function(data) {
            // Update global next page variable
            hasNextPage = true;//.hasNext;
            // Loop through all items
            for (i in data) {
                $("#newItems").before(
                // Do something with your json object response
            }
        },
        error: function(data) {
            // When I get a 400 back, fail safely
            hasNextPage = false
        },
        complete: function(data, textStatus){
            // Turn the scroll monitor back on
            $(window).bind('scroll', loadOnScroll);
        }
    });
};

For you html markup all I need to add is an anchor div with an id of “newItems” and include the infinite scroll script above. 

And this is my view that handles the initial page and the ajax infinite loading:

def debate_archive(request):
    user = request.user
    debates = [i for i in Debate.objects.all().order_by("-id") if i.opinion_set.count() >= 2]
    paginator = Paginator(debates, 10)
    if request.method == 'GET':
        if request.is_ajax():
            if request.GET.get('page_number'):
                # Paginate based on the page number in the GET request
                page_number = request.GET.get('page_number');
                try:
                    page_objects = paginator.page(page_number).object_list
                except InvalidPage:
                    return HttpResponseBadRequest(mimetype="json")
                # Serialize the paginated objects
                resp = serialize_debates(page_objects)
                return HttpResponse(json.dumps(resp), mimetype='json')
    debates = paginator.page(1).object_list
    return direct_to_template(request, 'debate_archive.html', locals())

I reuse Django’s built in Paginator class to know that I am serving back a certain sub set of the entire list of objects. It’s like pagination without pagination that happens automatically as you scroll! When I’m out of items I respond with a 400 which calls the error function in the ajax request which turns off the infinite scroll.

A couple things I noticed:

  • If you only add a small piece of additional content, this method may result in a ton of ajax requests. This has to do with the event being bound to the user reaching a certain area by scrolling. Since not much additional length was added it keeps triggering the event when scrolling. I’m sure you can find away around that.
  • You don’t need a separate url conf to set this up, just handle it in the same view using the is_ajax() function to determine if it’s from the infinite scroll. Add a some data to the GET ajax request and parse it in the django view. Keeps it all very tidy in my opinion.

This is what powers the infinite scroll found here: http://www.timeoutdebate.com/debate/all/

    • #django
    • #jquery
    • #infinite scroll
  • 4 months ago
  • 21
  • Permalink
  • Share
    Tweet

21 Notes/ Hide

  1. stunninglyinsane liked this
  2. distance liked this
  3. eat-sleep-repeat liked this
  4. torrobxx liked this
  5. emileeyou89 liked this
  6. v-ous-etes-belle liked this
  7. yeseniauio09 liked this
  8. brendaca83 liked this
  9. tiffany3451 liked this
  10. e-mechanism liked this
  11. nickthejam liked this
  12. joeconyers liked this
  13. alexkehayias posted this
← Previous • Next →

About

Blogging about hacking code, life, and music.

Me, Elsewhere

  • @alexkehayias on Twitter
  • Facebook Profile
  • Linkedin Profile

Twitter

loading tweets…

I Dig These Posts

  • Photo via marksbirch

    Every so often in my web ramblings, I come across an interesting tidbit. While not meant to be an endorsement of Automattic, I find it interesting...

    Photo via marksbirch
  • Post via franciscohui
    Some thoughts on pacing your life

    We live with contradictions. Which are okay for the most part, except when we’re not aware of them. It is a source...

    Post via franciscohui
  • Photoset via lifeandcode

    hasablog:

    GitHub stickers! Awesome gift :]

    Photoset via lifeandcode
  • Photo via franciscohui

    skewed. (via Porca Miseria)

    Photo via franciscohui
See more →
  • RSS
  • Random
  • Archive
  • Mobile

Effector Theme by Carlo Franco.

Powered by Tumblr