I blogged about the Spry 1.5 preview a few days ago and finally made time to whip up a quick demo of one of the new features - Session Handling

First and foremost - let me explain exactly what is meant by this. As you know, ColdFusion can't alert you when your session expires. It is a server side event. So obviously Spry can't get the notification from the server.

Instead what Spry supports is noticing a particular result from the server. So imagine a site with a login system. Typically you hit the site. Log in. Access the data. Now imagine you sit there on a Spry-ified page and let your session time out. You click to load a new page of AJAX data and Spry throws an error. Why? Because the back end returned a login form instead of a proper XML (or JSON) result.

So what to do? Well you now return a message to your AJAX requests. This message is the literal string: session expired. It doesn't need to be in XML. If Spry sees this as the result of a data request, it will then fire off an event. So consider this simple page:

<div spry:region="mydata">

<div spry:state="loading">Loading...</div> <div spry:state="error">Oh crap, something went wrong!</div> <div spry:state="expired"> <strong>Your session has expired!</strong> </div> <div spry:state="ready">

<p> <table width="500" border="1"> <tr> <th onclick="mydata.sort('name','toggle');" style="cursor: pointer;">Name</th> <th onclick="mydata.sort('age','toggle');" style="cursor: pointer;">Age</th> <th onclick="mydata.sort('gender','toggle');" style="cursor: pointer;">Gender</th> </tr> <tr spry:repeat="mydata"> <td style="cursor: pointer;">{name}</td> <td style="cursor: pointer;">{age}</td> <td style="cursor: pointer;">{gender}</td> </tr> </table> </p>

<p> <a href="javaScript:mydata.loadData()">Reload</a> </p> </div>


I have a loading, error, and ready div, along with a new expired div. If Spry sees "session expired" in the result, it will display that div automatically. (And you could include a nice link to the login page of course.)

To see a demo of this, visit this link. Click the reload link a few times, then simply go idle for 45 seconds. Click the Reload link again and you will (hopefully) see the session expired message.

How did I handle this? In my onRequestStart in Application.cfc I used this code:

<cfif not structKeyExists(session, "loggedin") and findNoCase("people.cfm", thePage)> <cfcontent type="text/html" reset="true"><cfoutput>session expired</cfoutput><cfabort> </cfif>

Notice that I check both for the session variable as well as the page. For any other page I want to force the user to the login form, but for AJAX requests I want to display the proper message. You could make this process easier by using a URL format like xml.foo.cfm for all AJAX requests. (I do something similar for my Model-Glue site.)

By the way - curious about the cfcontent? I discovered something interesting. Right now Spry is very picky. If you have any whitespace before or after the session expired message, it won't work. My Application.cfc did make use of output=false in both the cfcomponent and cffunction tag. Yet somehow I was still ending up with white space. My theory is - and I'll try to prove this tomorrow - is that when CF encountered the cfabort in onRequestStart, it didn't have a chance to "cleanup" the white space the method had generated.