Angular UI Sortable for Managing Sort Order

In my newest position I've been learning AngularJS. After diving in for a little over two months now, I'm seriously loving it, and wondering why I didn't seriously look at it much sooner.

One of the things it has taken a bit to get used to is that Angular does some things differently. I love Bootstrap but, like all other plugins, Angular's MVC approach has you do things "the Angular way", which can take a bit to break old habits. Luckily for us there are projects like Angular UI to help take the pain out of these sort of things.

One of the very few things that I use jQueryUI for is it's Sortable, Draggable and Droppable plugins. Angular UI has modules for these too. In this example, we're going to use the Sortable plugin for easy Drag n Drop display order management.

Using Drag n Drop for display order management is a fairly standard task. In the old days, we used up and down arrows that would typically be links, firing calls back to the server for database interaction and the refreshing the page for the new order. This was long, tedious, and a horrible user experience. Drag n Drop takes care of that. It allows the user to quickly define the order of things prior to ever sending data back to the server.

This demo isn't going to get into the server side mechanics of any of this, but rather the client-side stuff. First we'll start with the Bootstrap sample template (we'll use the Bootstrap CSS for basic layout stuff in our example). Don't forget to take out the Bootstrap JS file, and we're going to load the jQuery file up at the top ("why" will become clearer later).

view plain print about
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <title>Bootstrap 101 Template</title>
9 <!-- Bootstrap -->
10 <link href="css/bootstrap.min.css" rel="stylesheet">
12 <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
13 <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
14 <!--[if lt IE 9]>
15 <script src=""></script>
16 <script src=""></script>
17 <![endif]-->

19 <script src=""></script>
20 </head>
21 <body>
22 <h1>Hello, world!</h1>
24 </body>

A requirement of the Angular UI Sortable plugin is the actual jQueryUI sortable plugin, and it's dependencies. Luckily we can download a really trim file, giving us only what we need. We will insert the JS file in our document head, directly after our jQuery file.

view plain print about
1<script src="/path/to/file/jquery-ui.min.js"></script>

After that, we drop in the CDN link for AngularJS:

view plain print about
1<script src=""></script>

And then we need the Angular UI sortable. I haven't found a CDN for this one, so you'll have to install it locally:

view plain print about
1<script src="/path/to/file/ui-sortable.js"></script>

And finally, let's create a file to put all of our application logic:

view plain print about
1<script src="/path/to/file/sortable-app.js"></script>

In review, and inventory of our code show us that:

  • We're loading the Bootstrap CSS
  • We're loading some shivs, for handling HTML 5 stuff in IE 9 or earlier (good luck with that)
  • We're loading jQuery, and our chopped down version of jQueryUI
  • We're loading Angular, the Angular UI Sortable plugin, and a file for our application

Our app file is empty right now. Let's get it started by initializing our Angular application. We do this by implementing our app as an Angular module:

view plain print about
1angular.module( "sortable", [ "ui.sortable" ] )

Basically this says our app is called "sortable", and it has a dependency on "ui.sortable". That part was easy enough, but now we have to associate the app with our display. We do this by modifying our opening html tag:

view plain print about
1<html lang="en" ng-app="sortable">

The next thing I'll do is create a controller for the next part of our app.

view plain print about
1.controller( "ListController", function ( $scope ) {

view plain print about
1<body class="container" ng-controller="ListController">

We created a controller, and associated it with the body of our document. You can assign a controller to any element within your document, but this is a pretty simple example, so we're going simple here.

We need some data. Ordinarily you'd probably pull some data from the server, but for our demo we'll just create an array in our controller. The variable will be within the controller's scope, making it available to the block of our view within the ngController's elements.

view plain print about
1$scope.bands = [
2 {
3     name: "The Beatles",
4     rank: 1,
5     mode: "view"
6 },
7 {
8     name: "The Who",
9     rank: 2,
10     mode: "view"
11 },
12 {
13     name: "The Jimi Hendrix Experience",
14     rank: 3,
15     mode: "view"
16 },
17 {
18     name: "Led Zepplin",
19     rank: 4,
20     mode: "view"
21 },
22 {
23     name: "The Doors",
24     rank: 5,
25     mode: "view"
26 }

view plain print about
1<body class="container" ng-controller="ListController">
3<!--- The "bands" are available inside this block -->

Now that we can access our controller's variables, let's go ahead and output them to our screen:

view plain print about
1<div class="container-fluid">
2     <div ng-repeat="band in bands">
3         <div ng-if="band.mode == 'view'" class="row well">
4             <div class="col-xs-2">
5                 {{band.rank}}
6             </div>
7             <div class="col-xs-10">
8                 {{}}
9             </div>
10         </div>
11         <div ng-if="band.mode == 'edit'" class="row">
12             <div class="col-xs-10">
13                 <input type="text" class="form-control" ng-model="" placeholder="Band Name...">
14             </div>
15             <div class="col-xs-2 text-right">
16                 <button type="button" class="btn btn-primary" ng-click="addBand( band )">Add</button>
17             </div>
18         </div>
19     </div>
20 </div>
21 <hr>
22 <div class="text-right">
23     <button ng-click="createBand()" class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span></button>
24 </div>

OK, I need to slow down a minute. Let's explain some code here. First, I loop over the bands for output. If it's in "view" mode, it shows you the rank, and the name. If it's in "edit" mode, then you see a text box and a button. Lastly, there's a button at the bottom for adding new bands.

There are two methods tied in here. Let's add them both to our controller:

view plain print about
1$scope.createBand = function () {
3    var band = {
4        name: "",
5        rank: $scope.bands.length,
6        mode: "edit"
7    };
8    $scope.bands.push( band );
12$scope.addBand = function ( band ) {
14    band.mode = "view";

Nothing crazy here. We aren't doing any server-side stuff in this demo, so all we're trying to say here is "create" will put a stub object last in our bands array, while "add" will change a step's mode from "edit" to "view".

You can try that out now, if you want. Clicking on the "Plus" button at the bottom will add a new line for you. Type in a Band Name and then click that line's "Add" button. Each time you hit "Add", the mode changes to "view", and you see the display order followed by the Band name. You can add as many bands as you like, but so far we still can't re-order them, and anyone who knows me knows that as much as I love The Beatles, Jimi is number one in my book.

You'll remember that we already have the Angular UI Sortable plugin available to us. We included the code, and the dependency, now we just need to implement it. On the div that contains our ngRepeat loop directive, just add the directive call for the Angular UI Sortable:

view plain print about
1<div ui-sortable ng-model="bands" class="container-fluid">

This adds the directive to the container, as well as defining the model involved. ngModel is critical here, or it won't work. If you reload your page right now, you'll find that you can Drag n Drop rows backwards and forwards with ease. But you're not done. Just for grins, hit your "Plus" button for a form row, then try to drag it. It's not easy to grab it, but it can be done. Suddenly you're trying to re-order stuff that isn't ready for re-order!

This is easily bypassed, by adding some configuration to your sortable. The jQueryUI Sortable has it's own API and configuration options, and you can easily apply them to your Angular UI Sortable as well. First, create a configuration object in your controller. We don't need much, just something that identifies what our drag handles are (if there's no handle, it can't be dragged):

view plain print about
1$scope.sortConfig = {
3    handle: ".well"

We aren't applying the well class to edit rows, so this will exclude them. All we have to do is tell our directive to use this config:

view plain print about
1<div ui-sortable="sortConfig" ng-model="bands" class="container-fluid">

Now, if you reload and try it again, you'll see that you can no longer Drag n Drop the edit rows.

But, as you continue to drag items around, you'll notice that your display order column of data is way out of wack after a bit. The order should still be "1, 2, 3, etc", but now it's just a jumble. You know that the output is tied to your model, by accessing the band.rank, so as items get dragged around the rank needs to get updated. This can easily be done by watching the bands variable in the controller. We can set a method that says "when this changes, update it":

view plain print about
2    "bands",
3    function ( newValue, oldValue ) {
5        for ( var i = 0; i < newValue.length; i++ ) {
7            newValue[i].rank = i+1;
9        }
11    },
12    true

The $watch function allows you to set model listeners. Here we are looking for any change to the bands array in the $scope. Since bands is a complex data type we include the "true" to match objectEquality, meaning it will watch it "deeply", for any change, and fire when it changes. We're looping every item in the array, and resetting the rank according to it's new position in the array. The rank may never have changed (each time a new row is added this will also fire), but the overhead is pretty minimal, and it's a simple way to ensure the display order is always right.

That's it. Sample Code can be pulled from the download link. If you have questions, comments, or war stories, just hit me with a comment below.

Re-Imagining BlogCFC

Team CF Advance is dedicated to providing and maintaining Open Source software built in CFML. We welcome anyone to get involved, whether it's writing code, creating tests, or assisting with technical documentation, any contribution is a good one. There's already a decent list of ongoing projects that we are working on or maintaining.

On that track, how about giving us a little feedback. Let us look at a re-imagining of BlogCFC. BlogCFC was the first Open Source CFML based blogging platform, and still shares a wide install base. In that knowledge, it is important to consider not only maintaining full feature support, but also maintaining support for existing linking structures, data integrity in data migration, as well as support for multiple platforms.

There are several other ColdFusion based platforms for blogging. Mura CMS provides a way of creating blog pages. Mura is not truly a blogging platform, per se, but does make it possible. Mango Blog is also a fairly pervasive blogging platform, providing some additional level of extensibility as well. ContentBox is another platform, based largely on the popular ColdBox framework. Like Mura, ContentBox is really a CMS, so not really designed to be a blog.

Knowing that these options exist, one question then becomes "Why do ColdFusion developers adopt WordPress or Ghost as their blogging platform?" I believe this comes down to three core reasons. 1) ColdFusion hosting can be expensive, 2) the complexity of these other ColdFusion based applications, or the learning curve involved in their customization and maintenance, is more than some of these developers want to undertake, or 3) the developer was just trying to learn something different.

Issue #3 doesn't factor into this discussion. The decision of any developer to expand their knowledge base and learn new languages is a good thing. Doesn't necessarily look good to have a largely ColdFusion topic specific blog hosted on PHP, but we aren't writing this to solely serve developers. We want to build an application that anyone can deploy for their use, whether it's a development blog, a political blog, or just something to journal your trip to Istanbul. 

So, you then have two main issues you possibly need to address: 1) Hosting, and 2) simple install, usage, customization, and maintenance.

Issue #1 will still be hard to address (Team CF Advance is already in talks with a hosting provider who may offer low cost Blog hosting with everything preinstalled), but it's worth noting for future discussions. Issue #2 is more easily addressed.

Proposals For Discussion

  1. The current BlogCFC is actually two applications, one desktop and one mobile. I propose that we look at a responsive site design for a single maintainable codebase that is then viewable from multiple screen resolutions and devices. I propose adopting Bootstrap as the client-side CSS framework, to assist in that task. (One contributor has already done this with the current version of BlogCFC, so we may get a branch for this one soon...)
  2. There is currently no set style guide for skinning sites in BlogCFC. First, I think it would be extremely beneficial to build a template converter system, that could take existing themes for WordPress, and possibly Ghost, and convert them to BlogCFC themes. There is already a huge number of available WordPress themes out there, and the Ghost theme base is expanding daily as well. If we can leverage that, and make it dead simple for a user to implement, then we've covered a major hurdle to adoption. Ghost themes are the easier side of the coin, as their themes are already in Bootstrap, and already responsive designs. Second, a base template with well thought out HTML architecture and a solid CSS naming convention, that is then thoroughly documented, should make it easy for a user to upload a stylesheet that would completely customize their blog. At some point, we could even build a module for theme customization directly in the admin. And, with all of it, we heavily review page architecture to completely maximize SEO visibility.
  3. I think BlogCFC would thoroughly benefit from a server-side framework. I propose using FW/1 with DI/1. FW/1 (and DI/1) is extremely powerful and light weight, operates as a very natural extension of ColdFusion's built in application framework, and it's subsystem architecture lends well to extension/addition of new modules. I'm not positive, but we may also be able to leverage it's routing capabilities when considering legacy link support.
  4. I think we definitely need an "override" service architecture, where all instantiated objects are (at inception) blank objects that extend our base objects. This is used for individual developer customization, in a directory that never gets updated (other than the addition of new objects). Our tests should always pass, in development. Any individual overrides are the responsibility of that developer, and them running our tests should allow them to identify holes in their changes with any upgrade.
  5. I think we should employ REST services for Ajax interaction, and SOLR for site indexing and search. I do not propose the use of ORM. I think it is very important that our SQL is handwritten, well optimized, and that our indexes are carefully chosen for high availability/performance.
  6. I propose using AngularJS as a client-side JS interaction framework for the "admin" side of the blog, for data-binding and interaction. I think it best to avoid it on the front-end, in favor of generated code bits and more favorable SEO. Bootstrap should be sufficient for any "site" front-end functionality.
  7. I think we put considerable effort into the user stories centered around UI/UX, especially in terms of the admin area.
  8. I think that we generate output, where possible. Blog posts are, ultimately, static bits of page content.
  9. I think that we build in a simple plugin architecture, allowing others to contribute to furthering the platform by creating new add-ons that just be "dropped in".
    1. As with all projects overseen by Team CF Advance, we will be including tests for BlogCFC, written in TestBox. This will allow us to build out the project iteratively, testing each step along the way, to ensure that one patch doesn't break other parts of the system.

      Again, none of this is in stone. Just some random thoughts to get the ball rolling. This is just to really start the discussion, so please share your feedback. We already have a working group within Team CF Advance, who is contributing to this discussion. Ultimately these projects are community driven to fulfill a need, so knowing what you want is critical to the process. This also doesn't deter us from any ongoing patching efforts. If anyone has begun writing any patches, please let the team know so we aren't duplicating effort anywhere (or just join The Team).

Firefox, IE, and Why Browser Testing is Vital

OK, I made a mistake. I know, my wife will be amazed that I admit that, but it does happen. Testing another developer's code, I missed a critical error. Consider the following bit of code:

view plain print about
1cValue = $("#StartDate").val();
2cMessage += $.trim(StartDate).length == 0 ? "Start date is required.\n" : "";

Do you see it? The conditional, in the ternary operator, should be looking at cValue, but what the developer had intended to rename that variable. There is no StartDate variable in the script, so it should error out as undefined.

And, in Internet Explorer, it does error. StartDate doesn't exist. But, I screwed up. I tested this code in Firefox, and it didn't throw an error, even though that value was empty. You know why? Well, if you put StartDate in the Firebug console, instead of undefined it gives you this:

view plain print about
1<input id="StartDate" type="text" name="StartDate" />

Yes, that's right, because StartDate was an exact case match to the id of an element in the DOM, it returned the actual DOM element (which, by the way, is a valid string with a length).

Now, I'm not going to complain about who's right and who's wrong in this scenario (the value of StartDate), but it does underline the importance of testing in all browsers.

Once Bitten...

ColdFusion UI: cfwindow

Not sure why I forgot to blog this, but a few weeks back Ray Camden told everyone that he wasn't going to tell you to stop using ColdFusion UI tags anymore. Instead, he and Adam Cameron started the ColdFusion UI the Right Way project. This project is a collection of articles and demo assets to show people that you can use other methods for displaying these dynamic client-side "widgets" in your applications, without using the CFUI tags.

Why? Well, it was a nice concept, but honestly (and in my continuing opinion) ColdFusion doesn't need to do UI. Yes, cfoutput, and looping over queries is fine, but tags like <cfform>, <cfpod>, and <cfwindow> are the devil's work. There have been long running issues with letting ColdFusion write your HTML, CSS and JavaScript for you, the chief among them being that they're bloated, buggy, limited, and (ultimately) unnecessary. You have a much finer degree of control over your application, and how it functions, when you write it yourself.

The CFUI tags were provided to allow the lowest common denominator (i.e. someone who can't really write code) to crank out something that works. They are not intended for skilled developers who write web sites and applications for a living.

And so, Rey kicked off the project with an article on replacing <cftootip> with the jQueryUI tooltip plugin, and I wrote the next article on replacing <cfwindow> with Bootstrap's modal plugin. I just checked the repository, and now there are also articles for <cfajaxproxy> and <cfdiv>.

The idea of the project is to show you a) that it's possible to do these things without the CFUI tags, and b) show you examples using a variety of libraries, to reiterate that you aren't limited to a single option.

Build A Better ColdFusion App: Simple Conditionals

In really large apps, every line of processing can become critical. Every small process can add up, in terms of overall overhead. Especially in high traffic apps. Sometimes, the little things can really make a difference. Even your simple code might be...simpler. Take the following example:

view plain print about
1<cfset mySelections = "1">
2<cfif #mine# eq "0">
3    <cfset mySelections = "0">

I saw something like this in code this morning. Right off, the first thing you see is that all of the variables are unscoped, forcing the server to do a scopeCheck() to find out which scope each variable is a part of. Then there's the unnecessary bits to go along with it, like setting a variable, then checking another to reset the variable based on a condition. There's also the bit where the one variable is unnecessarily hashed. On top of all of that, variable assignments are one of those things it just makes more sense to write in CFScript. Let's take a look at how this might be improved:

view plain print about
1REQUEST.mySelections = (URL.mine) ? 1 : 0;

One line of code. Less keystrokes. Clearer references, and logic.

The "mySelections" variable, in this instance, is a part of the REQUEST scope (I upper case all variable scopes, to make them easier to spot when editing code).

In this situation, "mine" was a URL variable, param'd further up the page. We've used short-circuit boolean logic in our conditional statement. For those that don't understand that, any numeric value other than "0" is evaluated to true. If the value is "0", then it is false.

And speaking of numeric values, you don't need to quote them. Even though ColdFusion would figure it out, a quoted value is a string. Don't quote numeric, and don't quote Booleans.

We use the URL conditional inside of a ternary operator. Ternary operators were introduced in ColdFusion 9. The basics of this are, if the conditional is true, then use the value after the question mark. If the conditional is false, then use the value after the colon.

Finally, there's no need to hash the URL variable. You only need to hash variable references as part of output, or when they are used inside of quotation marks in code.

Now comes the really fun part. There really isn't any need for REQUEST.mySelections at all. Since the value or URL.mine was param'd, further up in the code, then the variable is always available here. Rather than copying that value to another variable (which takes up more memory), we can just reference URL.mine anywhere that REQUEST.mySelections was being used.

As you maintain your applications, it's always good to take some time and read through what's been written before. Refactoring little nuggets like this one, and a little testing, can eventually go a long way in preserving the life of your app and your server.

Out with 2013, and in with 2014

2013 was Exciting! I had several side contracts, which helped us buy a house. We left Jacksonville, and moved back to the Nashville area. I finally put some health issues behind me, allowing me to get out to some user group meetings again, as well as present. I put in a new topic for cf.Objective, which has been accepted. I picked up the camera I've been waiting a decade to buy, and jumped back in to photography with both feet. And, I carved in some time there to review a few books, do a CF Hour interview, and write a few blog posts (some even a little controversial). Now, there's downside here too. Heavy side contract work is not always conducive to a happy home. Buying a house, much less from another state (and the move that goes along with it) can be very grueling and stressful. Working at this kind of pace can bring on other health issues. The financial requirements of buying a house, moving state to state, setting up a new home, etc, make it impossible to do "other things" (like conferences, for instance). And, I still have several other book reviews I've yet to write, and didn't blog nearly as much as I would've liked. Well, you do what you can with what you have, and pray for the best. The two bright points in all of that are my wife, Teresa, and my daughter, Savannah, who continually support this crazed life, and without whom it really wouldn't be worth doing it all. I can never tell them enough how much I Love Them, nor just how much they mean to me. I never got the opportunity to talk about my conversation with Rakshith, concerning the future of ColdFusion. It was a great conversation, focusing quite a bit on Adobe's commitment to the platform, the strides in the education initiatives, and a focus on giving developers the tools (and language) they need to build better products. I think one of the greatest ColdFusion bits, to come out of this past year, was the creation of Team CF Advance. This group, entirely made up of volunteers, is working to produce Open Source applications and API's in ColdFusion. While it is still getting off the ground, the team has already made some pretty big strides. This is the kind of thing that will help bring ColdFusion back out front. I have high hopes, and high expectations, for what is to come from 2014. I've already committed to taking at least one picture a day, gotten seriously started on losing a few (too many) pounds, have several topics laid out for blog series, and am about to put some spit and polish on that preso I mentioned earlier. And that should be just the beginning. So, to all of my friends, colleagues, co-workers, and family, I wish you all the Happiest and most Prosperous of New Years.

What I'd Like To See Come Out of the ColdFusion Summit

So, the very first Adobe ColdFusion Summit is being held this week in Las Vegas, NV. What started out as a small conference, originally capped to 250 participants, is now nearly twice that size, with people coming from all over the world to attend.

We've had a lot of discussions here recently about What's Wrong With ColdFusion, and things that can be done to fix those perceptions. Ultimately, there's been a lot of positive feedback, some reasonable initial response out of Adobe, and a community that's started talking again.

What I'm hoping for is for that discussion to continue, hard, at the Summit. As much as I would like to be there, due to constraints I am unable to attend. So, I'm hoping that the community will come together to ask some hard questions. What really is being done to address the concerns brought up? How does this change current development practice, timeline, and direction? How soon can we expect to see x, y, or z? When, and how, is marketing of ColdFusion going to change?

It's important that we, the community, use this opportunity to speak to some of the engineers. "Why are we doing this? (in this new version) And not doing that?" We have to tell them what we think, and why, to assist in defining new directions. They're always gathering requirements, and you are the perfect focus group. The suits (management types that buy the licenses) can tell them that it should do this or that, but you (the developer) are the ones who truly know the things that are needed.

I know that I've talked a lot about "Adobe" ColdFusion. I am an Adobe Community Professional, so I have to choose my words carefully sometimes. Ultimately, any positive changes are changes that push innovation, competition, and advancement of the platform. In that vain, the Team CF Advance initiative, to write, support, and contribute to Open Source software solutions written with ColdFusion, is one of the single greatest things to come out of our discussion. (Big kudos to Denny Springle [with a side of Corfield], for pulling this idea back out of the hat and getting it up and running) Any time, and assistance, that anyone can give, is a good thing. While we need people to write code, we also need people that can assist with requirements gathering, documentation, and other things. Of all of the suggestions pushed in these discussions, this is the one that we (the developers) can have the most say and control.

Why I Like, and Use, CFScript

Many, many moons ago, I began a journey to learn web development. Actually it was a re-acquaintance, as I had gotten side tracked for a few years in a poor business partnership, having to catch up on how much things had changed. During that time, HTML had moved for v2 to 4, CSS was the crazy new thing replacing font and center tags, Dynamic HTML was making JavaScript hot again, and the browser wars were making life impossible.

Back then I was on the LA Tech Edu JavaScript mailing list (sadly retired, years ago). This guy named Peter Paul Koch was a major contributor to the list, and just ramping up this little site called QuirksMode. Scripting, though somewhat nightmarish with the browser wars, was actually a lot of fun. My first shopping cart was completely JS based.

I have always pushed for full parity between cfscript and tags, because scripting is more natural to me, in terms of writing programmatic logic. Sure, cfoutput and cfloop make a lot of sense in the middle of html display code, but CFC's don't (typically) contain display code, being data access and model objects.

I have issues with the implementation of CFScript. I find that there are a lot of functions of similar actions with completely different naming conventions, and argument requirements, and more. I think these things need to be addressed. That said, if I have to call the function anyway, I prefer script to tags when it's outside of display. It's a more natural approach, to me. 99 times out of 100 I end up with less lines of code, and find the logic more defined, clear cut, and easier to understand.

It's not for everyone. There are many that just plain hate cfscript, and that's their prerogative. But I will continue to use cfscript, and my examples will show that, because I personally find it a better way to write code. If it's not your preference, that's fine, you're welcome to translate my examples to tags if you need to, but for me this is how I do it. (For the record, many of the newer functions are not identical, under the hood [base Java code], as their tag counterparts, and some scripted functions have been proven to have better performance than their tag counterparts. There are benchmarks for this out there, somewhere, if you feel strongly enough to go look for them. I just take it on my experience with using it.)

Build A Better ColdFusion App: When The Var Doesn't Exist

Author's Note: Due to some of the feedback below, I'm going to remove a bit of example regarding paraming objects (see the feedback). Some have actually benchmarked where this creates overhead, rather than improvement of performance, so I'm going to stick with simple variables as this is researched further.

So, let's kick off this round of "Build a Better CF App" with a simple bit of code that you might see quite often in an app:

view plain print about
1<cfif NOT StructKeyExists(FORM, "isactive")>
2    <cfset FORM.isactive = false>

Simple, right? Probably dozens of these hanging around in your code. Now, let's look at a simpler form, that also gives us the added benefit of type checking.

view plain print about
2    param name="FORM.isactive" type="boolean" default=false;

What? Huh? Yeah, this makes sense. See, a checkbox type formfield doesn't actually get passed on form submission if it isn't checked, so chances are you're running this same code, in one way or the other, to default that value for you. Utilizing the param here (cfparam in tag form, but who's using tags outside of display stuff anymore? [hint, hint]) is really the better way of handling this.

  1. You get a default value for the variable
  2. The default is overridden, if the variable actually occurs
  3. If the variable does exist, the param ensures that it is of the proper type
  4. But wait, let's throw in another similar bit of code for good measure. How many times have you seen something like this?:

    Just doesn't feel right, does it? Especially when ColdFusion already gives us a way to handle this scenario:

    view plain print about
    1public com.mysite.User function getUser (required string firstName, required string lastName, numeric userID=0) {
    2    // More code
    3    return LOCAL.User;

    You can apply a default value to any argument of a function, utilizing your arguments just as you would a param.

    Now, there may be some valid reason for not paraming a variable, and using conditionals in some way similar to those above. They're few and far between, but there are exceptions to most every rule, so you'll need to evaluate that when the time comes.

New Series: Build A Better ColdFusion App

One common complaint, among opponents of ColdFusion, is the poor code that's out there on the web. I would counter that there's a ton of bad code out there in most any language (I know, I've written some of it), but I do "get it". ColdFusion, as powerful a language as it can be, also has an extremely low barrier of entry. It was created in such a way that anyone who could write HTML could turn around and write an application in ColdFusion (hence the language design decision to use a tag syntax).

Well, just because you can write code in one way, that doesn't necessarily mean that you should. There are thousands upon thousands of blog posts, articles and books out there showing people how to do various things in ColdFusion. Many (not all) are cobbled together rather quickly, offering up functional examples on how to do this or that. And, while awesome that someone bothered to take that time and share that knowledge, they didn't always consider best practices in their examples. After all, it was just a quick example, right? You wouldn't just copy and paste it into your editor. You'd tailor it to your application's needs, right?

Well, no. Many of us have copied some bit of code and just dropped it in without revision. And often it just stays like that, until it causes some sort of issue. To top it all off, chances are you copied and pasted the same bits of code into other areas of your app, or even into new applications, again without revision.

So, I want to start a new series here at Cutter's Crossing. I'm going to call it "Build A Better ColdFusion App", and in each article I want to highlight some small bit of best practice advice, with some code examples that match up accordingly. It won't be a "Tip of the Day" bit or anything, and the articles may come at any time, but they'll all get a common header, and I'll try to group them together so they're easy to find. If you have suggestions for some of these tips, or topic areas you think would be a good fit, please fill out the Contact Form and drop me a note with your suggestions.

By The Way: I'm not perfect. I might put up something and it's hosed too, or you might have suggestions on how to do it differently and/or better. Please, call me on it. We're a community of professionals, and want to put out info of value for any and all.

Previous Entries / More Entries