Easy Rich Internet Applications With ColdFusion 8

Share this article

The term Rich Internet Application (RIA) was coined by Macromedia (now Adobe) in 2002. An RIA is a web application — it runs inside a web browser, but looks and feels more like a desktop application. Gartner analysts Mark Driver, Ray Valdes, and Gene Phifer describe RIAs as “the next evolution of the Web” (PDF, 56KB).

Some of the properties that differentiate an RIA from a traditional web application are:

  • a richer user experience
  • cross-browser consistency
  • the ability to load data without having to refresh the page

Several different technologies can be used to create RIAs, including Adobe Flash, Adobe Flex, and Ajax. With ColdFusion 8, Adobe has given developers new tools to quickly and easily create RIAs that are either based on the Flash platform, or use plain old HTML and rely upon Ajax. This article will focus on the new Ajax family of tags and functions; I’ll guide you with step-by-step instructions through the challenge of building your first RIA — a simple user manager application — using Adobe ColdFusion 8.

Requirements

If you’d like to play along at home, here’s what you’ll need:

To follow along at home, download and unzip the code archive to the web root of your local development environment (the files exist in the RIA folder).

Getting Started

Before we get started, we need to set up a ColdFusion data source. Our application will make use of another ColdFusion 8 feature — an Apache Derby database. Apache Derby is a Java relational database management system that can be embedded within an application. By making use of Derby for our database, we minimize the need to install any additional software, thus ensuring compatibility across multiple operating systems.

Our first step is to set up a data source that will be used by ColdFusion to read and retrieve information from the database. Here’s how we set up a data source:

  1. Log into the ColdFusion Administrator.
  2. Navigate to Data & Services and click on Data Sources.
  3. In the form at the top of the page, enter the text “RIA” (without the quotes) in the field labeled Data Source Name.
  4. In the field labeled Driver, select Apache Derby Embedded.
  5. Click the Add button.
  6. On the next screen, you’ll be asked for the absolute path to the database folder. Set your path to the following: {path to web root}/RIA/database/RIA.
  7. Add a brief description (this step is optional).
  8. Finally, click the Submit button to create the data source.
Viewing the Demo Application

We’re now ready to take our demo application for a test run. Point your web browser to http://{web root}/RIA, and you should see a page that looks similar to Figure 1.

Figure 1: A grid, automatically generated by ColdFusion, displays a list of users

You’ll notice that our grid is nicely formatted — it displays alternating colors for the rows of data (known as zebra stripes), pagination controls, and even allows for column sorting (you can test this by clicking on the header of the column you wish to sort).

To launch a user detail window, click the New User button, or double-click any row in the grid — a User Information dialog box will launch, as illustrated in Figure 2.

Figure 2. A User Information window launches from the data grid

You’ll notice that the form appears within a modal window — a window that prevents a user from interacting with the underlying page. Enter or change some user data, and click Save User — doing so will close the window, and the data grid will be updated to reflect your changes.

Let’s break the code that we used to create this page into small chunks. We’ll starts with the code for displaying the grid, which is located in the file index.cfm.

Displaying a Grid with <cfgrid>

Normally, displaying a grid or table that has sortable columns and pagination requires a considerable amount of code (even with other frameworks). But with ColdFusion 8, it’s as simple as using the following ColdFusion tags:

 <cfgrid  
name="userGrid"  
 format="html"  
 pagesize="5"
preservePageOnSort="true"            bind="cfc:com.user.UserService.getAllUsers( {cfgridpage}, {cfgridpagesize}, {cfgridsortcolumn}, {cfgridsortdirection})"
sort="true"
stripeRows="true">
 
 <cfgridcolumn name="USERID" header="ID" display="false" />
 <cfgridcolumn name="FIRSTNAME" header="First Name" width="200" />
 <cfgridcolumn name="LASTNAME" header="Last Name" width="300" />
 <cfgridcolumn name="EMAILADDRESS" header="Email" width="220" />
 <cfgridcolumn name="PHONE" header="Phone" />
</cfgrid>

That’s all we need to do! There’s no JavaScript — there’s not even any HTML. All we need are a few lines of ColdFusion code. Let’s look at what each of the attributes in the cfgrid tag represents.

  • name – This attribute specifies the name of the grid. This also how you reference the grid within JavaScript.
  • format – This attribute determines the format that ColdFusion should use to build the grid. To create an AJAX grid, as we’ve done in the above example, specify “HTML”.
  • pageSize – This attribute defines the number of items to display per page.
  • bind – This attribute tells ColdFusion from where to retrieve the data that populates the grid. In the above example, we’re telling ColdFusion to use the method named getAllUsers in a ColdFusion Component (CFC) named UserService in the com/user/ directory. Note that when we’re invoking CFCs in ColdFusion, we use the dot notation to specify the path to the CFC. Also note that we’re passing in some arguments to the getAllUsers method, namely {cfgridpage}, {cfgridpagesize}, {cfgridsortcolumn}, and {cfgridsortdirection}. These variables describe the current state of the grid, and how we need to retrieve our information to sort or paginate the grid.
  • sort – This attribute tells ColdFusion that the columns are sortable.
  • preservePageOnSort – This attribute controls whether the current page should be redrawn when the user performs a sort of the data (for example, when a user is viewing page 2, and they resort the data, show page 2 of the new dataset). If you don’t set this value, the grid will be reset to page 1 whenever the grid is sorted.
  • stripeRows – This attribute tells ColdFusion to alternate the row colors.

There are many other attributes that can be used to dictate how the grid will look and behave. For more information, check out the LiveDocs for the cfgrid element.

The next group of tags, <cfgridcolumn>, provides ColdFusion with information about the columns that we wish to display.

  • name – This attribute contains as a value the name of the element (query column) that will be used to populate this column.
  • header – This attribute is the text that is displayed in the column header.
  • width – This attribute specifies the width of the column.

Note: The userID is not displayed
You may notice that our data source retrieves a userId column, but hides it with the attribute display="false". The value of userId is used to uniquely identify this user in our database — we need this value for a selected row so that we can retrieve and display all of the user’s information in the User Information window.

There are many other attributes that can be set to dictate how a grid column will look and behave. For more information, check out the LiveDocs help for <cfgridcolumn>.

Let’s now take a look at the CFC that’s referenced in the bind attribute of our <cfgrid>. There are several methods here that we use to retrieve and save individual users. There’s also a method that retrieves all of our users in order to populate the <cfgrid>, and it’s this code that we’ll dissect next.

Retrieving All Users with queryConvertForGrid

Here’s the code for our queryConvertForGrid method:

<cffunction name="getAllUsers" output="false" access="remote" returntype="struct">  
<cfargument name="cfgridpage">  
<cfargument name="cfgridpageSize">  
<cfargument name="cfgridsortcolumn"  />  
<cfargument name="cfgridsortdirection"  />  
 
<cfset var qRead="">  
 
<cfquery name="qRead" datasource="ria">  
SELECT userId,firstName,lastName,emailAddress,phone  
FROM  users  
<cfif len(arguments.cfgridsortcolumn) and len(arguments.cfgridsortdirection)>  
ORDER BY #arguments.cfgridsortcolumn# #arguments.cfgridsortdirection#  
<cfelse>  
ORDER BY lastName ASC  
</cfif>  
</cfquery>  
 
<cfreturn queryConvertForGrid(qRead, cfgridpage, cfgridpageSize) />  
</cffunction>

This is a very basic function that accepts four arguments:

  • cfgridpage
  • cfgridpagesize
  • cfgridsortcolumn
  • cfgridsortdirection

These arguments match the arguments that we specified in the bind attribute of our <cfgrid>.

One thing that’s worth noting about the <cffunction> tag is the access attribute. Any time you use Ajax to retrieve data from a CFC, the function that you call must have the access attribute set to "remote".

The function runs a very simple query against the users table in our database, and uses the arguments cfgridsortcolumn and cfgridsortdirection to order the results accordingly. If both of these values are empty strings, the results are sorted by last name.

Finally, we use <cfreturn> to return the value returned from the queryConvertForGrid function. queryConvertForGrid is a native ColdFusion function, and exists solely for the purpose of taking the results of a query and formatting them in a way that they can be used to automatically populate a <cfgrid>. This function takes three arguments:

  • the query result
  • the page number requested
  • the page size

It returns a ColdFusion structure that’s formatted in such a way that the <cfgrid> can easily interpret and display the data.

Adding a Listener to the Grid

Now we’ll explore the task of opening the details window. Before we delve into the details, lets look at these two lines of code from index.cfm:

<cfset ajaxOnLoad("initGrid") />  
<cfajaximport tags="cfform" />

The first line simply tells ColdFusion that the first time an Ajax call is made, it should run the initGrid JavaScript function. The second line tells ColdFusion that the ColdFusion elements we’ll be using will require that we load some libraries in the main page.

The initGrid JavaScript function simply adds a listener to the grid. With this listener in place, the showUser JavaScript function will be called when a row is double-clicked. The code for initGrid looks like this:

function initGrid(){  
 var grid = ColdFusion.Grid.getGridObject("userGrid");  
 grid.on("rowdblclick", showUserForm);  
 }


The first line in the initGrid method provides us with an instance of the grid named userGrid, which is the value we specified in the name attribute of the <cfgrid>.

The second line sets the listener for the rowdblclick event, and specifies that the showUserForm function should be called when this event occurs. ColdFusion actually uses the Ext JS JavaScript library to create the grid, so rowdblclick is an event that's native to the grid object. More information about the Ext JS grid object can be found at the ExtJS site.

Now that we've told the grid to run showUserForm when a row is double-clicked, let's look at the code that displays the details window.

Displaying a Details Window

First up, here's the code that comprises the showUserForm method:

function showUserForm(){  
   var userId = ColdFusion.getElementValue("userGrid", "userGridForm", "userId");  
   var url = "userForm.cfm?UserId="+userId ;  
   ColdFusion.navigate(url, "userWin");      
   ColdFusion.Window.show("userWin");  
 }

The first line in the method above retrieves the userId of the selected row. ColdFusion.getElementValue accepts three arguments:

  • the name of the control we want to look at
  • the name of the form that the items belongs to
  • the attribute we’re looking for

In this case, we’re telling ColdFusion to retrieve the userId attribute from the userGrid control in the userGridForm form.

We then set a variable named url, which will store the URL to which we’ll take the user. We append the userId as a parameter to the URL. This URL is used in the next line, which makes an http request to the URL and displays the result inside a <cfwindow> element named userWin. You can use the ColdFusion.navigate method to populate any HTML element on a page, such as a div. The last line will display the <cfwindow>.

Next up is the code for creating a JavaScript-based popup window using the <cfwindow> tag:

<cfwindow name="userWin" title="User Information" initShow="false" modal="true" center="true"></cfwindow>

Pretty simple, huh? Let’s look at what each of these attributes represents:

  • title – This attribute specifies the text that will appear at the top of the window.
  • initShow – This attribute can be used to control whether or not the window is initially visible.
  • modal – This attribute specifies whether the popup window is modal or not. Remember, modal windows prevent the user from interacting with the underlying page.
  • center – If this attribute is set to true, the popup window will be centered on the screen.

There are many other attributes that can be used to dictate how the grid will look and behave. For more information, check out the LiveDocs for <cfwindow>.

The next part of our application that we’ll look at is the form.

Creating the Form

Here’s our code for creating a user form:

<cfparam name="url.userId" default="" />   
 
<cfset user = createObject("component","com.user.UserService").getUser(url.userid) />  
 
 
<cfform name="userForm">  
 <cfinput type="hidden" name="userId"  value="#url.userId#" />  
 <div class="formElement">  
 <label for="firstName">First Name</label>  
 <cfinput id="firstName" name="firstName"  value="#user.firstName#" />  
 <div id="firstNameError" class="error"></div>  
 </div>  
 <div class="formElement">  
 <label for="lastName">Last Name</label>  
 <cfinput id="lastName" name="lastName" value="#user.lastName#" />  
 <div id="lastNameError" class="error"></div>  
 </div>  
 <div class="formElement">  
 <label for="emailAddress">Email Address</label>  
 <cfinput id="emailAddress" name="emailAddress" value="#user.emailAddress#"  />  
 <div id="emailAddressError" class="error"></div>  
 </div>  
 <div class="formElement">  
 <label for="phone">Phone</label>  
 <cfinput id="phone" name="phone"  value="#user.phone#"  />  
 <div id="phoneError" class="error"></div>  
 </div>  
 <div><cfinput name="submit" type="button" value="Save User" onclick="submitForm()"><cfinput type="button" name="cancel" value="Cancel" onclick="ColdFusion.Window.hide('userWin')"></div>  
</cfform>

There’s nothing terribly complex going on here.

First, we use <cfparam> to initialize the URL variable to an empty string. In the line that follows, we create an instance of the UserService object and call the getUser method, passing in the URL variable named userId.

The rest of the code simply populates the form with the information retrieved from the database. If this is a new user, the result retrieved from the database will contain empty strings, so our form will be empty.

One other point that’s worth mentioning is how the Submit and Cancel buttons operate. The Submit button calls a JavaScript function named submitForm, while the Cancel button simply calls ColdFusion.Window.hide("userWin"), which hides the <cfwindow>. Under each form field, there’s an empty div with an id similar to "{formFieldName}Error". This id will be used to display any error messages that are returned when the form is validated.

The final point worth making about this page is that it contains no JavaScript. Since this form will exist within our main page, we can store all of our JavaScript references there.

Processing the Form

Let’s take a look at the submitForm function in index.cfm:

function submitForm() {   
clearErrors();  
ColdFusion.Ajax.submitForm("userForm", "userForm_submit.cfm", submitCallback, errorHandler);  
   }

The first task performed by the function above is to call the clearErrors methods, which clears any form validation errors that may exist in our form from previous usage. The second line of the code above performs the post — the ColdFusion.Ajax.submitForm method takes the values of all of the items in the form named userForm, and posts them to the URL userForm_Submit.cfm. When the server sends back a response, the submitCallback function is called, and should there be any errors, the errorHandler method is executed.

Next let’s take a look at the userForm_submit.cfm file. This is the file that we use to validate our form and save our user details:

<cfsetting enablecfoutputonly="true" />   
<cfset errors = StructNew() />  
 
<cfif form.firstName EQ "">  
 <cfset errors["firstName"] = "You must enter a first name." />  
</cfif>  
 
<cfif form.lastName EQ "">  
 <cfset errors["lastName"] = "You must enter a last name." />  
</cfif>  
 
<cfif NOT isValid("email", form.emailAddress)>  
 <cfset errors["emailAddress"]= "You must enter a valid email address" />  
</cfif>  
 
<cfif NOT isValid("telephone",form.phone)>  
 <cfset errors["phone"] = "You must enter a valid phone number" />  
</cfif>  
 
<cfif structIsEmpty(errors)>  
 <cfset createObject("component","com.user.UserService").saveUser(argumentCollection = form) />  
<cfelse>  
 <cfoutput><cfoutput>#serializeJSON(errors)#</cfoutput></cfoutput>  
</cfif>  
<cfsetting enablecfoutputonly="false" />

In this page, we’ve created a variable named errors that will hold any information relating to failed validation. The validation we’re applying in this example is quite simple — it checks to make sure that firstName and lastName are not empty strings, and that emailAddress and phone contain a valid email address and telephone number, respectively.

Once our data has been validated (assuming that our errors variable is empty), we can safely save it to our database. Once again, we create an instance of our UserService and call the save method, passing in the form scope as the argumentCollection. Our save method contains logic to determine whether we’re dealing with a new user (that needs to be inserted) or an existing user (that needs to be updated).

If our errors variable is not empty, it means that our data contains errors. We need to pass them along in a way that will indicate to the main page that we encountered problems. This is best accomplished using JSON (JavaScript Object Notation), and fortunately, ColdFusion 8 has a native function, serializeJSON, to serialize a ColdFusion object into a JSON string.

By wrapping this call to this function in <cfoutput> tags, we’re returning a serialized string that represents our error variable. There also exists a ColdFusion function named deserializeJSON that accepts a JSON string and returns a comparable ColdFusion data structure.

To see how we use the results from this page, let’s revisit index.cfm and look at the code in our submitCallback method:

function submitCallback(response){   
     var errors = ColdFusion.JSON.decode(response);  
     var valid = true;  
       
     for(i in errors){  
   document.getElementById(i+"Error").innerHTML = errors[i];  
   valid = false;  
     }  
 if(valid){  
   ColdFusion.Window.hide("userWin");  
       ColdFusion.Grid.refresh("userGrid", true);  
 }  
       
   }

As you can see, the submitCallback function takes one argument, which is the response that was returned from the server when the form was submitted. Our first task is to decode the JSON string that’s returned using ColdFusion.JSON.decode — this will take the JSON string and turn it into a JavaScript object. As you may have suspected, there also exists a function named ColdFusion.JSON.encode that accepts a JavaScript object, and returns a JSON string.

If there are any errors in the errors JavaScript object, we loop over the elements in the object and set the innerHTML of the corresponding div for the form field. (These are the same divs that are cleared when the clearErrors method is called.) If any errors are returned, we set the variable valid to false.

If there are no errors returned, and the form is valid, we can happily close the <cfwindow> with the method ColdFusion.Window.hide("show"). Finally, we refresh the grid using ColdFusion.Grid.refresh so that any changes that were made will be reflected in the grid.

The only thing we haven’t covered yet is how we display the form to create a new user.

Creating a New User

Our users can create a new user by clicking the New User button. This button calls the newUser JavaScript function:

function newUser(){   
 var url = "userForm.cfm" ;  
 ColdFusion.navigate(url, "userWin");      
 ColdFusion.Window.show("userWin");  
}

As you can see from the code above, this function is similar to the showUserForm function, with one exception — we’re not passing a userId in the URL. This approach will ensure that the <cfwindow> displays an empty form when it’s opened.

You may have noticed the minimal amount of JavaScript in our code; if you look at the source code, you’ll see a lot more. Whenever you use any of the ColdFusion Ajax components, ColdFusion will automatically pull in the JavaScript that’s necessary for your component to function.

Summary

It may seem like there was a lot involved in this example, but given what we’ve accomplished — a cross-browser compatible, rich interface for viewing and managing a list of users — there really wasn’t that much to it. Remember that our grid contains sortable columns and pagination, and we’re making Ajax calls to refresh the grid as well as to display and process our form.

All of this was achieved with four relatively small ColdFusion files and about 30 lines of JavaScript. I think that speaks volumes about ColdFusion’s capabilities for helping you create RIAs without getting bogged down in all the intricacies of JavaScript, Ajax, and browser compatibility issues.

This example merely scratches the surface of ColdFusion’s Ajax capabilities. For more information on creating Ajax applications with ColdFusion 8, check out the ColdFusion Developer’s Guide.

Scott StrozScott Stroz
View Author

After spending over a decade working as a paramedic, Scott decided it was time for a change and started down the path of web development. Currently, Scott is a Senior Software Architect at Alagad. He has been working with ColdFusion since version 5 and has been a Macromedia/Adobe Certified Advanced ColdFusion Developer since ColdFusion MX. He has developed and fostered a passion for Flex, and her half-sister, AIR. He is the author of Flogr, a Flex based ColdFusion log reader. Scott is also a blogger, author and frequent speaker at user groups and conferences on various Flex and ColdFusion topics.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week