File Generating and Letting Users Know It Really is Coming


For one of our current projects, we're building a "contact list" feature, i.e. a way for users to pull up lists of persons in the system. They have a choice of stock lists and can build their own custom lists. I might try to blackm persuade my partner to do a guest post on the rather awesome interface he built for that aspect. Meanwhile, part of my contribution was in building the visual displays of the lists, as well as the Excel and PDF download options.

Normally for an Excel or PDF, we would just link off to it and be done with it. However, it is relatively easy to build a list that can have over 1,000 records, so the file generation can take more than a few milliseconds. Our largest one, with nearly 6,000 rows in Excel, or over 100 pages in PDF, can take a good minute or two. So I thought it would be nice to show some sort of "processing" message to our users, so they would know it was churning and to keep them from constantly reclicking the link (and thereby just make it worse).

But then the question became how? While JavaScript is rather awesome, it can't detect when the file dialog window opens or things like that. So if I just threw up a message, how would I make it go away when the file is ready? I can't throw a JS command in the CFM that serves the file since I'm using cfcontent header to do said serving.

After a bit of hunting around, I found a few clues that led me to a fairly tidy solution that actually works quite well, combining JS with ColdFusion and using cookies.

So first, on the page that has the links, I add an on click even to the icons for the downloads that creates the appropriate URL and calls our function. Note: This snippet is just for the custom lists as a sample.

$("#MyCustom .contactListTable").on('click', ".pseudoLink", function(){
    var doDialog = false;
    var ContactListID = $(this).attr("ContactListID");
    myLink = CustomExcelLink + '/ContactListID/' + ContactListID + '/';
    loadMyLink();
});

The little loadMyLink() function calls up our processing message using the BlockUI jQuery plug-in, appends a token to our URL and calls it up, then it begins a continuous loop of checking for a cookie that has the same token.

function loadMyLink() {
    $.blockUI({
        message: '<h2><img src="/assets/images/icons/coffeemachine.gif" align="middle" /> Generating request, please wait...</h2>',
        theme: true
    });
    var token = new Date().getTime(); //use the current timestamp as the token value
    myLink = myLink + "MyToken/" + token + "/";
    window.location.href = myLink;
    /* keep dialog until file is generated */
    fileDownloadCheckTimer = window.setInterval(function () {
        var cookieValue = $.cookie('FILEDOWNLOADTOKEN');
        if (cookieValue == token) {
            window.clearInterval(fileDownloadCheckTimer);
            $.removeCookie('FILEDOWNLOADTOKEN', { path: '/' }); //clears this cookie value
            $.unblockUI();    
        }
    }, 1000);
}

On the ColdFusion end, at the end of all my file generating code, I add an extra bit to set a cookie with….you got it, our little token.

<cfcookie name="FILEDOWNLOADTOKEN" value="#MyToken#" />

Once the file is done, ColdFusion sets the token and continues to load the file. JS sees the cookie is there with the token now and removes the block.

The end result? If you click one of the file download options, you'll get a nice little message:

And when the file is ready, it will go away while the file download window loads:

I imagine some better JS gurus can tighten that code up even more, but it's working pretty well for us, so yay! Now obviously, we will also be using some caching techniques to speed things up even more, but for where we can't, this is a nice addition to give our users some feedback.