Exercise List: Procedural ColdFusion Code Complete (Phase I)
Click here to view the current Online Demo
Click here to view / download the current Code Base
Last night, I finished Phase I of my Exercise List journey into understanding Object Oriented Programming (OOP) in ColdFusion. Phase I was the "proceedural" phase; it was building the application in a quick, standard, proceedural way that does not take advantage of any sort of ColdFusion components or OOP principles. The important thing is that it laid the foundation on top of which I can now learn object oriented programming, not just for single objects, but most importantly, for object composition and relationships in the context of a small but highly applicable application.
Building Phase I took a little longer than I had expected because I was trying to keep the CSS fairly clean. After reading Bulletproof Web Design and Learning jQuery and having looked at the stuff Javi is doing, I wanted to really put some effort into making accessible forms and progressively enhanced functionality. Therefore, there are no tables in my forms (which is what I would normally do); instead, it is a strategic use of the Label element as well as many DIVs and the like. This was my first attempt, so I am sure it is not at clean as it could be, but I think, not bad for the first go in a new mind-set.
The thing that I am really excited about is the idea of progressive enhancement of the page's functionality. This was an idea that Javi introduced me to and then the book, Learning jQuery, really drove home; the idea is that to allow all users to properly experience the page you have to add all the Javascript functionality only after the document object model (DOM) has loaded. This way, if a user does not have Javascript enabled, they can still use the default rendering of the page without all the bells and whistles.
In my Add/Edit Exercise page as well as my Search page, I have Joint Actions separated out into their own little boxes. If you view these pages with Javascript enabled, you will see that checking a Joint box will cause the related actions to either slide up or slide down depending on the state of the checkbox. In order to make sure that non-Javascript enabled browsers can view the page, all of the boxes start out fully expanded. It is only after the page loads that I collapse the boxes and bind the click events to the Joint checkboxes.
This actually has a few advantages; not only does it make the page more universally accessible, it also makes the code both cleaner and easier to write. It's cleaner in the sense that you don't have all these OnClick tag attributes inline with your HTML. It also makes the ColdFusion code cleaner since you don't need a whole lot of CFIF logic to determine whether elements should have display "none" or "block". It makes the code easier to write because using jQuery and it's implicit iteration, the Javascript becomes extremely simple and separated out into one area with higher readability.
Also, as a side effect of using the jQuery and progressive enhancement, you don't have to worry about any Form Caching done by the browser. I am sure at some point, everyone has had to deal with FireFox keeping checkboxes checked even after a soft-refresh. This can cause issues because ColdFusion will view the FORM data as being different that the rendered FORM and therefore, mouse click events do not always act as expected. By using jQuery and progressive enhancement, however, you never have to worry about this because jQuery runs code at the end of every page request (including soft-refreshes) and because it works based on the rendered page, form caching becomes a non-issue.
Here is the code that I have at the bottom of the Search and Edit pages:
<!--- Progressively enhance page. --->
<script type="text/javascript">
$(
function(){
// Hide all the joint properties.
$( "div.jointproperties" ).hide();
// Show the joint properties for joints that
// have already been selected.
$( "label.joint:has( :checked )" ).next().show();
// Hoop up the clicks for the joint checks.
$( "label.joint input" ).click(
function( objEvent ){
var jInput = $( this );
var jProperties = jInput.parent( "label" ).next();
// If this is checked then show the actions.
if (this.checked){
jProperties.slideDown( "fast" );
} else {
jProperties.slideUp( "fast" );
}
}
);
}
);
</script>
It's almost too easy! I love jQuery.
Exercise List: Next Steps
Now that Phase I is complete, it's time to start getting into an Object Oriented state of mind. If you look at the Add / Edit Exercise query page as well as the Search query page, you will see that the logic here is not exactly simple. I am going to have to figure out how to capture the relationship between joints and exercises and how to access that relationship. For example, are the joints actions composed in the Exercise object:
Exercise.GetJointActions()
... or are they gotten from some sort of Exercise gateway / service:
ExerciseGateway.GetJointActions( ID = 1 )
Or are both of the ideas horrible? To be honest, I haven't the faintest idea. I have a whole host of ColdFusion Object Oriented Programming blog posts (by other people) in my "To Be Reviewed" bookmarks folder. I guess it's time I get reading.
Any and ALL advice would be greatly appreciated.
Want to use code from this post? Check out the license.
Reader Comments
Cool. But how and where did you define your request.attributes.
Thanks.
getting this error
Element ATTRIBUTES is undefined in REQUEST.
The error occurred in C:\xampp\htdocs\exercise\includes\_header.cfm: line 8
Called from C:\xampp\htdocs\exercise\actions\_error.cfm: line 12
Called from C:\xampp\htdocs\exercise\Application.cfc: line 246
6 : the original values, we can always use the other scopes.
7 : --->
8 : <cfloop item="REQUEST.Key" collection="#REQUEST.Attributes#">
9 :
10 : <!--- Escape values. --->
@I Rz,
Hmmm. It looks like there is an error happening before the request is available (or rather, before OnRequestStart() event has fired). I am not sure what is going on. I will dig into this.
@I Rz,
I have updated today's code-base. I put at CFTry / CFCatch around the header / footer include. I am not 100% happy with this, but I think it recovers from the error as best as I could without a ton of effort.
Thanks. Looking forward to llearning from you as you learn more. Your blog is awesome.