Patriots 45, Chargers 24

This would probably be as monumental of a championship game upset as we would ever see.  That is not going to happen.  New England will win by plenty and move on to destiny…

Giants 17, Packers 15

Again, this just has all the makings of a classic.  The Giants have found their stride and continue to play the role of Cinderella.  The Packers resilience this season has been extremely surprising.  This will go down to the wire, and right now, the Giants are wearing the lucky shoes.

Last Week: 3-1 vs spread, 3-1 outright.

Automatic server side validation in ColdFusion can be an extremely useful feature, particularly when you need to perform a set of rather common validation tasks.

Consider this cfform, with the server side validation code:

1
2
3
4
5
6
7
8
9
10
11
12
<cfform action="myform_action.cfm">
   Name: <cfinput type="text" name="fullName" required="yes"
                  message="Your name is required" validateat="onserver" />
   <br />
   Email: <cfinput type="text" name="emailAddress" required="yes" validate="email"
                  message="You must enter a valid email address" validateat="onserver" />
   <br />
   Confirm Email: <cfinput type="text" name="confirmEmailAddress" required="yes" validate="email"
                  message="You must enter a valid confirmation email address" validateat="onserver" />
   <br />
   <cfinput type="submit" name="save" value="Submit" />
</cfform>

Very simple, very neat. However the problem is with the output:

Default cfform error

This post deals with customizing the output, so that it shows up on the same page as the form, in a typical validation fashion.

We are going to tackle this by utilizing the onError() method of the Application.cfc. First, let’s start out with an extremely basic Application.cfc, to understand what happens when we implement the onError() method.

Consider this first rendition of the Application.cfc:

1
2
3
4
5
6
7
8
9
10
<cfcomponent name="Application">
   <cfset this.name="form_validation_app" />
 
   <cffunction name="onError" returntype="void">
      <cfargument name="exception" required="true" />
      <cfargument name="eventName" type="String" required="true" />
 
      <cfdump var="#exception#">
   </cffunction>
</cfcomponent>

When an automatic validation error is triggered, it is now caught by the onError() method (in fact, all application errors are now captured here). Let’s analyze the output.

Below is the dump of the exception object (internally, it’s actually not a struct), triggered by failing form validation:

Form validation error dump

Let’s analyze each key of this structure:

Detail
This is the exact output we saw on the default validation error page (the ugly grey error). Completely useless to us.
Message
This is the message that we see on the ugly grey error page. We could use this to determine if there is a validation error, however, if future versions of ColdFusion modify this message, our code would need to be updated.
StackTrace
Extremely long, ugly, gives you an idea about how CF is built on top of Java. But, actually, fairly useful. The first entry in the trace is coldfusion.filter.FormValidationException, which is the exception object thrown by ColdFusion when a form validation error occurs. It is highly unlikely that the name of this would ever be modified, so we could test to see if exception.stackTrace contains “coldfusion.filter.FormValidationException”, and trap a validation error using this.
Tag Context
Not applicable here
Type
Type of Application is extremely common, therefore, useless here.
errors
This is a key that is particular to this type of error. It is a bunch of <li> tags, or list items, which could be used in a list to display the error. This will be very useful to us, however, it would have been much more useful had CF provided us with an array of structures, with 1 key representing the name of the field in error, and the other key representing the message (this way our display of messages would be unlimited). However, this will suffice, so we will use it.

Now let’s modify the Application.cfc.

  1. We will trap validation errors, while throwing all other errors up to the next level of error handling (either a site-wide error handler or the ugly grey message).
  2. If we catch a validation error, we need to capture the exception.errors field, and forward the user to the page they came from (we can use cgi.HTTP_REFERER). Since we need to use cflocation to forward the user, we must put exception.errors into a persistent scope - we’ll use the session scope for this and delete the key immediately after we display the errors.
  3. We will also create a method to display these validation errors, right in the Application.cfc (you could certainly put it elsewhere; this is simply for ease of implementation.)
  4. Finally, we need to be able to pre-populate the form, using the submitted data (depending on business rules, the actual population can vary, i.e., we likely won’t populate password fields). To do this, we will simply create another temp session variable, and a function in the application.cfc to access this (and destroy it).

The new Application.cfc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<cfcomponent name="Application">
   <cfset this.name="form_validation_app" />
   <cfset this.sessionManagement = "true" />
 
   <cffunction name="onRequestStart" returntype="boolean">
      <cfargument name="targetPage" type="String" required="true" />
      <!--- Capture this instance of the Application.cfc into the request
      so that other pages can call custom functions on the Application.cfc --->
      <cfset request.app = this />	    
      <cfreturn true />
   </cffunction>
 
   <cffunction name="onSessionStart" returntype="void">
      <cfset session.validationError = "" />
      <cfset session.stFormData = structNew() />
   </cffunction>
 
   <cffunction name="onError" returntype="void">
      <cfargument name="exception" required="true" />
      <cfargument name="eventName" type="String" required="true" />
 
      <cfif isDefined('exception.StackTrace') AND isDefined('exception.errors')
      AND exception.StackTrace contains 'coldfusion.filter.FormValidationException'>
         <cfset session.validationError = exception.errors />
         <cfset session.stFormData = duplicate( form ) />
         <cflocation url="#cgi.HTTP_REFERER#" addtoken="false" />
      <cfelse>
         <cfthrow object="#exception#" />
      </cfif>
   </cffunction>
 
   <cffunction name="displayValidationError" access="public" returntype="void"
               output="true">
      <cfif len( session.validationError )>
         <ul class="validationError">#session.validationError#</ul>
         <cfset session.validationError = "" />
      </cfif>
   </cffunction>
 
   <cffunction name="getStFormData" access="public" returntype="struct">
      <cfset var stRet = duplicate( session.stFormData ) />
      <cfset session.stFormData = structNew() />
 
      <cfreturn stRet />
   </cffunction>
</cfcomponent>

And we now add 2 lines of code to our form page, above the cfform:

<cfset variables.stFormData = request.app.getStFormData() />
<cfoutput>#request.app.displayValidationError()#</cfoutput>

We can now reference variables.stFormData, to prepopulate each of the form fields that need to be prepopulated.

Now, our output upon an error is as follows:

Customized Error Message

We could further extend this now, to even perform custom validation in our action page, by simply using cfthrow (for example, when the email address and confirmation email do not match), and catching this cfthrow inside of our cferror. Of course, I leave that for you to do :)

Green Bay 24, Seattle 10

The Packers have won with an amazing defense this year, and a running back (Ryan Grant) who basically came out of nowhere.  Oh, and that Favre guy, he still has something left in the tank.

New England 38, Jacksonville 17

Seriously, do you really think the Pats have come this far just to lose to the Jags.  I love the Jags running game, but the Pats strength defensively is against the run.  I know Garrard has had a good year, but I don’t think he can single handedly win this game.

Indianapolis 30, San Diego 27

This has all the makings of being the best game of the Wild Card weekend.  In a back and forth game, I’ll take the Colts for two reasons (1) they’re at home, (2) Adam Vinateri can be all the difference in close playoff games.

NY Giants 27, Dallas 25

Well, maybe Indy/SD will only be the second best game of the Wild Card weekend.  The Giants have hit one hell of a stride in recent weeks, and if Eli Manning can continue to play like he has the last two weeks, mixed with the running attack of Ahmad Bradshaw and Brandon Jacobs, this will certainly go right down to the wire.  The big factor: what percentage will TO be for this game?

We have successfully moved servers.  New content to be posted shortly!

Currently, I have this site hosted on wordpress.com, but my plans for it are far too restricted by the limitations of keeping the site hosted on wordpress.

Tomorrow, I will be in the process of migrating to my own server, which will hopefully allow me to more easily control the UI, plus integrate with other applications besides simply Wordpress.

For my Fast Track class, if I have problems during the migration, I will be emailing you a set of resources to use in your ColdFusion/Web Application development.

Thank you.