Login Register

Mail Progress Bar

The people who run clickdammit.com are cheapskates. Their servers are Pentium Pros bought off Ebay in exchange for some Beanie babies. So Andy knows that users will click "Get Mail" and wonder what's taking so long.

This is a common problem in Web 2.0 applications. Hopefully your servers are faster than Pentium Pros, but even then you can't always be sure when response times will be slow. Since you're not submitting the form, you can't rely on the browser's spinning logo to tell the user something's happening.

Fortunately, Dijit has a progress bar for those situations. Andy doesn't have access to clickdammit's mail server yet, but he decides to sketch out the progress bar and write some Wait loops behind them to simulate delays.

First he places the progress bar where the placeholder text was:

<div id="fetchMail" style="opacity:0;visibility:hidden">
        <div annotate="true" id="fakeFetch" dojoType="dijit.ProgressBar"
                style="height:15px; width:275px;" indeterminate="true"
                report="fakeReport">
</div>
</div>

We make this progress bar hidden so it can be called up when needed. At first the progress will be incalculable since we don't know the number of messages to download. That's what "indeterminate=true" shows.

We have already stubbed out fakeDownload() and connected it to the Get Mail button. Now we can actually add some code to it.

var fakeDownload = function(){
	dojo.byId('fetchMail').style.visibility='visible';
	numMails = Math.floor(Math.random()*10)+1;
	dijit.byId('fakeFetch').update({ maximum: numMails, progress:0 });
	dojo.fadeIn({ node: 'fetchMail', duration:300 }).play();
	for (var i=0; i<=numMails; i++){
	    setTimeout(
                      "updateFetchStatus("+i+")",
                      ((i+1)*(Math.floor(Math.random()*100)+400))
            );
	}
}

First we turn on the progress bar, then pick a random number (1 to 10) of emails to download. Now to update the progress bar ... Andy looks up the dijit.ProgressBar widget in the Dijit catalog and finds under Methods:

Methods
update update progress information

Update looks good, and he consults the example before writing the update statement.

dojo.fadeIn does what you think. It fades-in an object but turning up the opacity from 0% to 100%. The "300" here is the number of milliseconds fadeIn should take to complete its job. 0.3 seconds sounds small, but it's enough to make the animation noticeable without stopping the proceedings.

Any adds the updateFetchStatus function, which will fire once for every email.

var numMails;
var updateFetchStatus = function(x){
	if (x == 0) {
		dijit.byId('fakeFetch').update({ indeterminate: false });
		return;
	}
	dijit.byId('fakeFetch').update({ progress: x });
	if (x == numMails){
		dojo.fadeOut({ node: 'fetchMail', duration:800,
			// set progress back to indeterminate. we're cheating, because this
			// doesn't actually have any data to "progress"
			onEnd: function(){ 
				dijit.byId('fakeFetch').update({ indeterminate: true });
                                // remove progress bar from tab order
				dojo.byId('fetchMail').style.visibility='hidden'; 
			}
		}).play();
	}
}

dojo.fadeOut looks a lot like fadeIn, but the onEnd property is new. It expects a function as its property. Here we add a function literal that removes the progress bar from the screen. But why put this in onEnd? Why not just put it after play()? Andy tried that first, and found the progress bar would blink out before it had completely faded. That's because fadeOut, like all Dojo animations, runs asynchronously. In other words, it kicks off the fadeOut and starts executing the next statement. FadeOut continues executing. So setting the duration to 800000000 would make the animation slow, but the browser would still be immediately usable.

Finally, we connect a function to ProgressBar's "report" extension point. Remember how we specified report="fakeReport" in the Progress Bar tag? Now we can fill it in. Report gets passed in a percent and expects a string to place on the progress bar.

var fakeReport = function(percent){
    return "Fetching: "+(percent*this.maximum) + " of " + this.maximum + " messages.";
}

Andy clicks on the Get Mail and sits back. It looks darn good! He clicks it a few more times just to make sure. Very nice. We're getting pretty close to a working demo to show off. Just a few more things need to go in place.

AttachmentSize
step5.html9.76 KB