Posted on April 28, 2014 by Chris Harrington

Page change progress bar for jQuery-enabled single page applications

Leaf is a single page application, which means that only a portion of the page changes when navigating between pages. This has a number of benefits that I don’t want do delve into at the moment, but suffice to say it trades (optionally) longer initial page load time for speedier navigation and potentially fancier page transitions. One of the downsides, however, is that the developer has to build his or her own method of informing the user that a page change is taking place. I’ve noticed recently that YouTube does an excellent job of this. It puts a “line” progress bar at the top of the page that shows up when you click on a YouTube video to watch. The line behaves like Safari’s progress bar; it jumps a little at first to say, “hey, your page load progress is here!” and then completes as the new content loads. It’s slick and subtle and I like it, and I’m going to show you how you can do it yourself.

To start with, I’m using the excellent Nanobar library. It’s what lets you put the progress bar at the top (or wherever) of the page. First, obviously, include the Nanobar javascript file in your SPA’s root page.

I’m assuming that your single page application content is being retrieved using jQuery’s ajax methods. If not, then this isn’t going to apply to you. To hook into the ajax methods, we’re going to use jQuery’s global ajaxSend and ajaxComplete functions.

var bar = new Nanobar({
    bg: "#4FB53C",
    target: $("div.bar-container")[0]
});
		
$(document).ajaxSend(function () {
    bar.go(15);
}).ajaxComplete(function () {
    bar.go(100);
});

First, we initialize the nanobar by specifying a colour via the “bg” property and a pre-existing container using the “target” option (div.bar-container in this case is just an empty div that spans the width of the document). Note that Nanobar requires a DOM element and not a jQuery element; the [0] lets us get the first DOM element from a jQuery selector. Once the Nanobar has been initialized, jQuery’s ajaxSend function allows us to tap into every ajax request that gets performed.

There’s no easy way to determine the actual progress of an HTTP request, so I’m sort of faking it here. On initialization of any ajax request, I set the bar to 15% width to indicate that a request has started. On completion, the bar is set to 100% width. Nanobar takes care of the fancypants animations. While I suspect there might be better implementations of a progress bar that deal with actual request status updates, I feel as though this gets us 90% the way there and is trivial to implement.

And hat’s it. Super easy to build. A caveat, here: the above implementation will trigger a progress bar for every ajax request you’re sending. That means that in the event you’re sending an ajax request when the user arrives at a new page, he or she will see multiple progress bars. To get around this, you can disable jQuery’s global ajax events (which we’re tying into) by specifying

global: false

in your ajax calls, as such:

$.ajax({
    url: "get/me/data.json",
    global: false
});

This will prevent the progress bar from firing for that request. Conversely, you can set your Nanobar to show up for only those ajax requests you specify by using the local variants of ajaxSend and ajaxComplete, again in the options. Here’s an example of the page navigation progress bar on Leaf: