How I Do Things: ColdFusion and Ajax Requests

I get a lot of questions about handling Ajax requests. What are some best practices? How do you format your requests? How do you taylor your functions in ColdFusion? Those sort of questions. We (the ColdFusion community) have embraced Ajax. Many of us spent so much time working mostly server side code on top of simple (and often poorly thought out and formatted) forms, but user habits have changed. And so have we. You have to move with the times to keep up in the digital rat race.

Let's start with the stuff most CFers already know; the server side stuff. When we make an Ajax request, most often we will hit a function within a CFC. We need data. You can hit a .cfm page, and return a bunch of preformatted HTML, but often that's a lot of data transfer when your really only need a few bits of data. HTML code can get heavy, what with all the tags and such. Similarly, you could return data in XML form (WDDX is native in ColdFusion). XML is sometimes a required format, for certain requests, but like HTML it can often be overly verbose. When working with server side requests from the client, you want to minimize data transfer as much as possible. That's why Flash performs best using the AMF format, and why most Ajax applications work with JSON.

When constructing your ColdFusion functions for remote requests, you don't have to write functions that can only be used via Ajax. In fact, that would probably be bad practice, as it would really minimize the code reusability of your functions. Basically, the only true requirement, at the server side, is that you set your function's access attribute to remote.

view plain print about
2 *    COMPONENT SomeComponent
3 *    Just some example component
4 *
5 *    @name SomeComponent
6 *    @displayName SomeComponent
7 *    @output false
8 */

9component {
10    /*
11     *    FUNCTION SomeFunction
12     *    This is just some function you've written
13     *
14     *    @access remote
15     *    @returnType struct
16     *    @output false
17     */

18    function SomeFunction(required string arg1, required numeric arg2) {
19        var retVal = {"success" = true, "message" = "", "data" = ""};
20        // some function stuff here
21        return retVal
22    }

That's it. Nothing to it. Did you see the required line? The one you need for making a remote request of this function?

view plain print about
1*    @access remote

Ok, we're off and running. Sort of. "Hey, Cutter, what's with returning a struct? I thought we were working with JSON?" Well, let me explain...

Have you ever worked on some Ajax call, loaded the page up in the browser, and nothing happened? You change variables, do this and that, and get nowhere? Finally you open up Firebug, watch the request, and see that you CF code has errored out for some reason. Instead of data coming back, the browser is getting the thousands of lines of HTML and Javascript that is the ColdFusion error display. In the immortal words of Charlie Brown: AAUUGGHH!

What happens if your user sees this behavior? Some variable isn't getting set when you think it is, or some db guy added or removed a column from your database without your knowledge. An error gets thrown, and you never even realize it. Ouch! Users are quick to abandon you. How can you gracefully handle these things?

Well, how do you deal with error handling within your application? If this answer is "I don't", then you might want to explore another career path. No, just kidding (kind of). If you don't use error handling, this is the perfect scenario to start. There is no reason why you're users should see (or, in this case, not see) these types of issues within your application. By carefully thinking things out, you can provide a better user experience.

view plain print about
2     *    FUNCTION SomeFunction
3     *    This is just some function you've written
4     *
5     *    @access remote
6     *    @returnType struct
7     *    @output false
8     */

9    function SomeFunction (boolean debug = false, required string arg1, required numeric arg2) {
10        var retVal = {"success" = true, "message" = "", "data" = ""};
11        var q = new Query();
12        try {
13            // do your query stuff, setting the result to the "data" key
14            if (!retVal["data"].recordCount) {
15                throw(type = "ourCustom", errorCode = "RC_000", message = "No records were returned matching your criteria.");
16            }
17        } catch (any excpt) {
18            LogTheError(excpt); // Custom error logging for us
19            retVal["success"] = false;
20            if (!ARGUMENTS.debug) {
21                retVal["data"] = ""; // Clear the "data" key, so we don't pass unneeded bits back to the client. Override this by passing 'debug' into the request.
22                if (excpt.type eq "ourCustom") {
23                    retVal["message"] = excpt.message;
24                    retVal["errorCode"] = excpt.errorCode;
25                } else {
26                    retVal["message"] = "There was an error in making your request, and our administrators have been notified.";
27                    retVal["errorCode"] = "UN_001"; // Internal error code for an undefined error
28                }
29            } else {
30                retVal["message"] = excpt.message;
31                // and anything else you might want
32            }
33        }
34        return retVal;
35    }

Now, there are probably better ways to write your catch statements, but I'm just trying to lay some foundation here. The basic idea is, taylor a message to send back to your users in the event of a failure. "ErrorCode?" Many enterprise products have custom error codes they use to denote that a specific error has occurred (like the above 'RC_000' for no returned records).

So, we have a success key, denoting whether the requested ColdFusion function did what we wanted. We have a data key that we use for returning the data generated by the request. And, we have a message key that we may, or may not, use only in the event of an error. We've also used and errorCode in this scenario, only in the event of an error. "Cutter, something doesn't look right?"

view plain print about
1// You use the quotes and this struct access notation to preserve the casing of key names, which is important in JavaScript
2    var retVal = {"success" = true, "message" = "", "data" = ""};
3    ...
4    retVal["message"] = excpt.message;

That should be the basics of the server side stuff. But, then the question comes, "What if our model isn't under the web root? What if the model CFC's aren't web accessible?" OK, fair enough. Then you'll need a proxy CFC. Let's regroup a sec, and show what this might look like.

view plain print about
2 *    COMPONENT SomeComponent
3 *    Just some example component
4 *    This example sits outside the webroot, in a 'com' directory that's mapped in the CFIDE
5 *
6 *    @name SomeComponent
7 *    @displayName SomeComponent
8 *    @output false
9 */

10component {
11    /*
12    *    FUNCTION SomeFunction
13    *    This is just some function you've written
14    *
15    *    @access public
16    *    @returnType struct
17    *    @output false
18    */

19    function SomeFunction (boolean debug = false, required string arg1, required numeric arg2) {
20        var retVal = {"success" = true, "message" = "", "data" = ""};
21        var q = new Query();
22        try {
23            // do your query stuff, setting the result to the "data" key
25            if (!retVal["data"].recordCount) {
26                throw(type = "ourCustom", errorCode = "RC_000", message = "No records were returned matching your criteria.");
27            }
28        } catch (any excpt) {
29            LogTheError(excpt); // Custom error logging for us
30            retVal["success"] = false;
31            if (!ARGUMENTS.debug) {
32                retVal["data"] = ""' // Clear the "data" key, so we don't pass unneeded bits back to the client. Override this by passing 'debug' into the request.
33                if (excpt.type eq "ourCustom") {
34                    retVal["message"] = excpt.message;
35                    retVal["errorCode"] = excpt.errorCode;
36                } else {
37                    retVal["message"] = "There was an error in making your request, and our administrators have been notified.";
38                    retVal["errorCode"] = "UN_001"; // Internal error code for an undefined error
39                }
40            } else {
41                retVal["message"] = excpt.message;
42                // and anything else you might want
43            }
44        }
45        return retVal;
46    }

And the remoting proxy...

view plain print about
2 *    COMPONENT SomeComponent_Remote
3 *    Just some example proxy component
4 *
5 *    @name SomeComponent_Remote
6 *    @displayName SomeComponent_Remote
7 *    @output false
8 *    @extends ""
9 */

10component {
11    /*
12     *    FUNCTION SomeFunction
13     *    This is just some function you've written
14     *
15     *    @access remote
16     *    @returnType struct
17     *    @output false
18     */

19    function SomeFunction (boolean debug = false, required string arg1, required numeric arg2) {
20        return Super.SomeFunction(argumentCollection = ARGUMENTS);
21    }

"Wait a second! I thought you said this post was about Ajax? Where's the JSON? Where's the Javascript?" Well, Ajax is useless without the data, right? Now that you have your CFC's and functions setup, let's look at the Javascript to make our requests. First we'll look at a basic JQuery Ajax call. First, let's set a global JS variable in the page.

view plain print about
2    param type = "boolean" name = "URL.debug" default = false;
4    savecontent variable = "REQUEST.adder" {
5        WriteOutput('<script type="text/javascript">var debug = #URL.debug#;</script>');
6    }
7    REQUEST.addHeaderOutput &= REQUEST.adder;
10<cfhtmlhead text="#REQUEST.addHeaderOutput#" />

Next we'll setup our Ajax call.

view plain print about
2    url: '/my/cfc/location/SomeComponentRemote.cfc'
3    dataType: 'json',
4    data: {
5        method: 'SomeFunction', // The method we're calling
6        returnFormat: 'JSON', // Give us the return as JSON
7        debug: debug, // the global default 'debug' set earlier by ColdFusion
8        arg1: 'This is my argument',
9        arg2: 42
10    },
11    success: function (response, status, options) {
12        if ( {
13            // Do something with the data
14        } else {
15            // This means the request failed, and should contain
16            // a 'message' key, to present to the user, and an 'errorCode' key
17            // that you're application might act on
18        }
19    }

Here's the same basic Ajax request, using Sencha's Ext JS.

view plain print about
2    url: '/my/cfc/location/SomeComponentRemote.cfc',
3    params: {
4        method: 'SomeFunction', // The method we're calling
5        returnFormat: 'JSON', // Give us the return as JSON
6        debug: debug, // the global default 'debug' set earlier by ColdFusion
7        arg1: 'This is my argument',
8        arg2: 42
9    },
10    success: function (response, options) {
11        var response = Ext.util.JSON.decode(response.responseText)
12        if ( {
13            // Do something with the data
14        } else {
15            // This means the request failed, and should contain
16            // a 'message' key, to present to the user, and an 'errorCode' key
17            // that you're application might act on
18        }
19    }

I'm always surprised at how few CFers know this little bit. In case you missed it, the key piece to your request parameters comes down to one important argument.

view plain print about
1returnType: 'JSON'

When this argument is passed in the Ajax request parameters, ColdFusion will automatically serialize your native ColdFusion response objects into JSON. This is what allows you to set your returnType to a struct in your function definitions.

Most of this stuff has been around for quite a while. Some use it a lot more than others. Some are just afraid of client side stuff in general. There's a ton of material out there on how to do these things. This is my way of working with it. That doesn't make it right, or better than anybody else's. It's just what I've developed as a working pattern over the years. How do you handle it?

New Job, New Home, A Lot of Work

It's been a very busy year, up til now. Work ramped up in February, contracting me for additional hours for a month and a half straight, after which I've worked on a sting of side projects. This helped me finance a move to Jacksonville, Florida. My new (daytime) job is full-time telecommute, which allows me to put my desk anywhere. Teresa wanted to get back to sunshine and beaches, being tired of the cold and snow of Tennessee winters, and chose Jacksonville for it's location and proximity to family and friends. Jacksonville is a great area, and we nailed a terrific place in Fleming Island. I like it because there's lots of tech (user groups and such), and it's not far from other tech centers (Orlando, Tampa, Atlanta, etc). It doesn't hurt that I can maintain a year around tan or that the beach is a short drive away.

A lot of work has come my way, often tacking an additional 40 to 60 hours a week on top of my normal day job schedule. Often I'll take a project that takes a week or two, then take a few weeks off to spend with the family (and catch up on my reading). I have a list of posts I need to write, due to exposure to some projects I hadn't previously been exposed to. Part of that already started with some exposure to the DataTables JQuery plugin, but I'm also lining up posts for jqGrid, jsTree, and the cfUniForm project. Evernote is filling up with little tidbits. The most difficult piece is coming up with the time to write examples. I'm particular about writing well formed code and documentation, which is why my posts sometimes get spaced out a bit.

One of the things I have discovered, in my exposure to these other projects, is how much I miss working with Ext JS day-to-day. JQuery UI is a good project, but lacks the maturity of Ext JS, and is missing too many key components for writing web applications (Data Stores, Grid, Tree, Menus, Tooltips, etc). My exposure to those other projects was an attempt to fill needs for which Ext JS would have been better suited, while locked into using JQuery UI. The JQuery UI team is working on closing that gap, but there is a lot of catch up necessary to match the breadth and power of Ext JS.

Speaking of Ext JS, Packt Publishing asked me to write the next Ext JS book on my own. While very flattered, I had to carefully weigh what that commitment would mean. Ultimately, I could not justify committing seven and a half months to writing the book with all of the other responsibilities I have right now. I will write a few articles for Packt (as part of my contract on the last book), but feel like I can continue to create blog content that would be more timely (no six month editorial process) and have a greater reach, and do so as my schedule permits without being a burden on my family. Sencha has already announced What to Expect in Ext JS 4.1, and recently put Ext Designer 1.2 in Beta, so there's a lot to talk about here.

Last, but definitely not least, I'm following all the buzz about the upcoming ColdFusion "Zeus". A quick Google Search already brings up a ton of info that Adobe has put out regarding the next version of the ColdFusion server platform, and it looks to once again be a significant release. Some of the big things already mentioned have been the move from JRun to Tomcat, the retirement of Verity in favor of Solr, the upgrade to Axis 2, and the inclusion of closures in CFML. That's just some of what's coming, as Adobe appears to be giving more and more detail during the various conferences through the year (and you never know the whole story until it's released).

Using The DataTables JQuery Plugin

For adminstrative applications, most of my readers know I'm a huge proponent of the Ext JS library. But for front-end, consumer facing sites, I'm often pushed to use JQuery. JQuery is very light weight, and wonderful for DOM manipulation, but it isn't a component library. When you want widgets for advanced data display, you have to use something like JQueryUI. Unfortunately, JQueryUI doesn't yet have a grid component (though they are working on it). So when I recently needed a dynamic, paging data grid, I started looking for something that used server-side data requests and could be skinned using the ThemeRoller. That's when I came upon the DataTables plugin.

It took me some time to figure out the works of how the plugin makes server-side requests. What I found was that, by default the plugin passes an extreme amount of data on a request, and not typically in a format very conducive for our needs. I also had to find a way to pass the method name and data returnFormat needed. That's when I discovered that I could override it's default request. Once I figured that out, I wrote a method to parse the data to create a request object more conducive to a ColdFusion Component request. It passes the following arguments along in a request:

  • iDisplayStart - The number of the first record in the requested set.
  • iDisplayLength - The number of records to return in the requested set.
  • sEcho - A DataTables request identifier, to be echoed back with the return.
  • aoSort - If present, this will be a JSON string representation of sort columns and orders. It's an array of objects:
    • colName - the column name
    • sortDir - the sort direction (asc|desc)

After getting data to my CFC, I had to build my paging query. For my example here I wanted to use the MySQL database I use for my blog, so this was a learning experience for me. The biggest trick for me was getting the TotalCount of records, as this is extremely different from MS SQL, requiring two separate SQL statements for the query and the count. Since DataTables can also sort off of different columns, I needed a way to dynamically set the ORDER BY clause of the query. You can't bind parameters to the ORDER BY clause, but you want to protect your server from SQL injection attack, so you have to validate that part of the request (especially as it's an ajax request, which would be easier to manipulate). Pete Frietag came up with a little regex expression that could be used in this case.

We set up our component to return a structure in the following format:

  • success - A boolean to denote success or failure of the request.
  • message - Only returned if the request fails, a message to state why the failure occurred.
  • totalCount - The total number of records available for the filters applied.
  • result - The paging query.

The last piece of the puzzle was back on the client-side again, where the ColdFusion return had to be put back into a format that can be consumed by the DataTables plugin. This was actually very easy because of the way that ColdFusion returns query data.

Once I had these methods, I wanted to find out how to write a feature plugin for DataTables. One where I could identify additional config arguments in DataTables, and have it automatically work. I contacted Allan Jardine, who wrote DataTables (and has some great web dev tools on his site). He never wrote in that capability, saying that the method override was the only way to make this happen. What I did discover was that I could add options to the standard DataTables config. I created a new option for DataTables, oCFReaderDT, which takes an object of options. Only one argument is required, "method", to define the method to call in the CFC request. I also setup the processor to accept an option, "sForm", as a string selector of a form whose values you may need in the request (i.e.: 'form#myForm'). Then I wrote a custom function that encapsulated the previously written methods into one method, that could then be used as the value of the "fnServerData" option in the DataTables configuration object.

In the download link below is a zip file with all of the files for the example, which has been heavily commented so you know what's going on. Though written for ColdFusion 9, I have included both scripted and non-scripted CFC's. I hope you find this useful, and please leave any comments/questions/suggestions through the Comment Form or Contact links below.

New Custom Tag for Google Maps: CFGMap

Two years back I had to write a new mapping implementation for my former employer, who wanted to move away from MapQuest. We chose Google Maps, for a number of reasons. I wrote the implementation using Scott Mebberson's implementation, the Google Maps Tag. I was quick and easy, and ultimately we had to ditch it at the last minute. Why? Google's licensing at the time was too restrictive for our use case. Running almost 2,000 sites of of one codebase, we would have had to get a separate license key for each site, or get an enterprise license through Google. We were going down that path originally, but the cost at the time was almost $40k, and required some work on their part that they couldn't make our deadline (during the holidays), so when the autorenewal kicked in on (cheaper) MapQuest we just rolled with it.

Last month my former employer once again wanted to get rid of MapQuest. First we looked at our implementation, realizing that the same hurdles were in place. Next we looked at ColdFusion 9's new cfmap tags. That implementation works the same way, requiring the API key per domain. Luckily, I remembered seeing a tweet from someone about changes to Google's Maps API. A change that wouldn't require an API key anymore. So, I went to check it out.

The latest version of the Google Maps Javascript API is very nice, and has one very significant change.

The JavaScript Maps API V3 is a free service, available for any web site that is free to consumers.

This was perfect, as all of our sites were free to consumers. The first thing I did was try to make some adjustments to my initial implementation from Scott's tags. This didn't work, as there were some major differences in Google's new implementation. I ended up rewriting the entire implementation to work with the new API, creating my own custom tag. In forking Scott's code, I had to keep the license the same, which allows me to put it back out to the community at large (and with the approval of my old boss).

CFGMap is now available on RIAForge for download. My simple example source code is included with the download, and all code is heavily documented. My example uses JQuery for the basic DOM manipulation involved, but JQuery is not required to use the tag itself. You'll want to pay special attention to the testmap.js file, which shows how you can access your map object to plot directions and stuff. The tag puts a map on the page, and plots the points you've fed to it. It will even trigger a callback method, that you define, for passing lat/lng info that's been goelocated back to your database, reducing the geolocation hits on subsequent map visits.

It's only the first go-around with the updated library, and I'm sure that changes will need to be made at some point. I welcome any and all feedback, questions, and suggestions.

Development Ties

On the last day of CFUnited 2005, a group of us were out on the patio having a final drink together. I got into a conversation with Clark Valberg about linguistics. I was a translator in latter half of my time in the military, and Clark was asking if I thought my experience with learning another language had helped me in learning to be a better developer?

I absolutely agreed. I have an aptitude for languages, and always have. It's something I've picked up, and I can generally get to a point where I can effectively communicate (at least on the simplest of terms) within a very short time. Programming isn't much different, if you think about it. When I first got into computing again, after leaving the Army, I was teaching myself ten different programming languages at the same time. I had a lot of catching up to do, being out of the game for so long, so I picked up some books, found online resources, and took to the task of getting up to speed.

Maybe that's why there are so many talented developers outside the US. In the US, we aren't required to learn another language out of necessity, whereas in most other countries of the world (not all, but most) it is very commonplace for people to speak two or more languages.

You can kind of apply this in the reverse, to some degree, as well. Those who only learn one development platform may be limiting themselves. Knowing one programming language inside and out can be a good thing, but learning others can also open a developer to new ways of approaching a challenge. I've known many developers who knew a server-side language (ColdFusion, ASP, PHP, whatever), but never bothered to learn JavaScript, or how to write well formed XHTML. To me, that's limiting. Even crippling.

What are your thoughts?

Upcoming Book: Learning ExtJS

I've been rather quiet for quite a while now. I have a rather large side project I've been working on, written entirely with an ExtJS front-end and ColdFusion on the back-end. I'm hoping to get that into a QA phase in the next week or two. I also just celebrated my 39th birthday, my 8th wedding anniversary, my daughter is the rock star of the 1st grade (pulling straight A pluses in every category), and the holiday's are coming.

On top of everything else, I'm putting the final touches on Learning Ext JS, to go to press at the end of the week/beginning of next, and due out in December. I've stayed relatively quiet on this, as I wanted to wait until PackT, my publisher, officially released information on the book. Let me start by saying that a few years ago I never would have thought I'd be doing this much client-side development again. And I definitely wouldn't have imagined me contributing to a book about client-side development.

I began looking at ExtJS quite a while back, while contemplating how to "jazz up" and modernize some dated interfaces I was supporting. I thought that ExtJS was an exceptionally well thought out library of rich, consistant components and functionality. While I use JQuery almost exclusively for DOM queries and manipulation, I really didn't find enough consistency in the visual plugins at the time (this has improved with the latest round of the JQuery UI plugins). I began to learn of the real power of ExtJS, and became an even bigger fan when it was announced that Adobe was including it in Scorpio, the codename for ColdFusion 8, Adobe's first implementation of the ColdFusion web application platform since it's acquisition with the Macromedia merger. Sweet! A total win-win for me.

Back in June, PackT contacted me. It seems they had started to develop a book, but the primary author, Shea Frederick, had gotten bogged down in other commitments before being able to complete the project. Some Googling on their part led them to Colin Ramsay and myself, through Cutter's Crossing. So they contacted me to find out if I was interested. The timing on this was awful. I was just starting the previously mentioned side project, my daughter was on her very first summer vacation, and just a lot of things going on. But it was too good to pass up. Aside from the fame and glory (yeah, right!), I knew that there weren't any other books out there on ExtJS, and it would be an excellent book to get out there for all the people trying to learn this exciting library. After talking the pros and cons with Aaron West, and getting sign off from my family, I finally contacted the Jedi himself, Ray Camden, to get some info on the writing process. We talked about time (a lot), commitment (more), and fame (maybe a little) and fortune (nearly none). I finally went ahead and said I would do it.

So, here it is almost six months later. I took on the final three chapters of the book: working with data stores (think like browser cached data table sets), extending Ext objects to build your own custom components, and the book wrap-up, which covers all the little stuff many people miss because they aren't typically visible. Only one chapter has any server-side code (the data stores). PackT originally wanted to convert my ColdFusion examples to PHP, to conform with the rest of the book. This morning the publisher told me that they want to keep my ColdFusion examples, to show that the ExtJS library can work with any server-side technology.

So, they're taking pre-order now, just in time for the holidays. Let me know what you think.

A Small Bug In AIR?

Well, maybe. One of my co-workers, Andy Matthews, has been working on a small app, integrating BlazeDS with ColdFusion to push messages to an HTML/AJAX based AIR application. He and I spent several days configuring the server integration and piecing out the ins-and-outs of how the messaging works (big thanks to Andy Powell on this too). Andy (Matthews), coming from a design background, created this beautiful chromeless HTML interface, with a little JQuery magic thrown in to work with the bridge. That's where this possible bug reared it's ugly head.

The question is whether the bug is in AIR, or within the Flex/AJAX Bridge itself. Basically, if you've defined your transparency setting to true, within your App.xml file, then the load() method of the bridge will not call the function reference.

Andy has submitted the bug to Adobe. He also dropped Christian Cantrell and Ben Forta (hey, it's who he knows...) the following email about the issue:


I believe that I've discovered a bug in AIR and I'm not sure who else to send this to.

I've been working on an HTML/JS based AIR application for my company using BlazeDS. I'd finally gotten everything working in a test environment when I went to port the working code into my already working transparent, custom chrome AIR app. Then it stopped working.

After debugging, I found the reason, or at least part of it. It appears that an AIR app which uses the FDMSBridge.swf provided by Adobe WILL NOT work when the app has transparency.

In my sample app ----------------- 1) I opened my sample code (without transparency), and compiled it. 2) I pushed a message to the gateway and the message was successfully received in the app. 3) I then changed the transparency setting in the App.xml file from false to true and recompiled the app. 4) I pushed another message to the gateway and received nothing.

In the final app --------------------------------------------- 1) Transparency was already set to true, so I compiled the app 2) I pushed a message to the gateway, and received nothing. 3) I then changed transparency to false, recompiled the app 4) Pushed a message and successfully received it.

Further, when the app first loads, it correctly displays the alert window when transparency is set to false, but not when it's set to true. ------------------------ Here's a small code sample:

view plain print about
1FDMSLibrary.load("FDMSBridge.swf", initBlazeDSCode);
3function initBlazeDSCode() {
4 alert('why me');
5 var cs = new ChannelSet();
6 cs.addChannel(new AMFChannel("cf-polling-amf",""));
7 consumer = new Consumer();
8 consumer.setDestination("ColdFusionGateway");
9 consumer.addEventListener("message", messageHandler);
10 consumer.setChannelSet(cs);
11 consumer.subscribe();
14function messageHandler(e) {
15 alert('got a message! I GOT A MESSAGE!');

The Year In Review

2007, The Year Of The Scorpio, was a fantastic year to be a ColdFusion developer. The release of ColdFusion 8 marked a new age in web application development, with so many new features and enhancements that should see some truly outstanding next generation applications in the years to come. As a community, the CF crowd has really been flourishing, with new releases in several major frameworks, the introduction of the RIAForge open source repository for Adobe related technologies, widely publicized adjunct technologies like Flex 3 and AIR approaching final release (spawning a new conference in 2008, showcasing all three technologies together), and the premier of our own developer's social networking site, ColdFusion Community. We saw the loss of the CFDJ albatross, while the Fusion Authority Quarterly, introduced at CFUnited 2006, has truly come out as an excellent ColdFusion developer's resource. And we can't forget our very own, ColdFusion specific, blog aggregator, ColdFusion Bloggers, introducing us to so many other great developers willing to share their knowledge and experiences, like the creative, and very colorful, examples provided by Ben Nadel.

I've always felt that a day without learning is a day that your dead from the neck up.I spent quite a bit of time this year learning new things, and sharing most. I've been slowly picking up Flex, put a little research into AIR, adopted JQuery heavily, run series of posts on developing on Apache and utilizing the outstanding components of the ExtJS library (the most trafficed posts on this blog). I tried to share some of the things I had learned about the new functionality of ColdFusion 8, started posting some General Coding Guidelines I've been writing for our company, and even got some first hand experience looking at the Current ColdFusion Job Market.

I look forward to sharing more in the year to come. I always look for, and appreciate, all of the feedback you readers send my way. I think the future for ColdFusion is extremely bright, and I can't wait to see what 2008 holds for us all.

My First ExtJS DataGrid Pt 7: Custom Cell Renderers

So, it's been awhile. No, I haven't forgotten you, I've just been busy with a lot of things. One of which has been implementing a new ExtJS DataGrid in a project I'm working on. Sure, there's a lot more going on, but that's becoming a nice front end piece. As previously promised, I want to look at a renderer.


ExtJS Nested Tab Set with Demo

Ok, following up on my last entry, here is the same nested tab set done with the ExtJS UI Library. I went the the "Build Your Own" section within "Downloads" and built a script for JQuery with the ExtJS Core and the TabPanel. I also downloaded the whole library so that I had all of the example scripts, css, and images. After this I included the following files in my document header (notice the pathing changes):


Previous Entries / More Entries