13 min read

(For more resources on ColdFusion, see here.)

There used to be long pages of what we called “spaghetti code” because the page would go on and on. You had to follow the conditional logic by going through the page up and down, and then had to understand how things worked. This made writing, updating, and debugging a diffcult task even for highly-skilled developers CFCs allow you to encapsulate some part of the logic of a page inside an object. Encapsulation simply means packaged for reuse inside something. CFCs are the object-packaging method used in ColdFusion.

The practice of protecting access

In CFC methods, there is an attribute called “access”.Some methods within a CFC are more examples of reuse. The sample code for _product.cfc is shown here. It is an example of a power CFC. There is a method inside the CFC called setDefaults(). The variable variables.field.names comes from another location in our CFC:

<cffunction name="setDefaults" access="private" output="false">
<cfset var iAttr = 0>
<cfloop list="#listLen(variables.field.names)#" index="iAttr">
<cfscript>
variables.attribute[#listGetAt(variables.field.names,iAttr)#] =
setDefault(variables.field.names,iAttr);
</cfscript>
</cfloop>
</cffunction>

The logic for this would actually be used in more than one place inside the object. When the object is created during the first run, it would call the setDefaults() method and set the defaults. When you use the load method to insert another record inside the CFC, it will run this method. This will become simpler as you use CFCs and methods more often. This is a concept called refactoring, where we take common features and wrap them for reuse. This takes place even inside a CFC. Again, the setDefaults() function is just another method inside the same CFC.

Now, we look at the access attribute in the code example and note that it is set to private. This means that only this object can call the method. One of the benefits to CFCs is making code simpler. The interface to the outside world of the CFC is its methods. We can hide a method from the outside world, and also protect access to the method by setting the access attribute to private. If you want to make sure that only CFCs in the same directory can access these CFC’s methods, then you will have to set the attribute to package. This is a value that is rarely used.

The default value for the access attribute is public. This means that any code running on the web server can access the CFC. (Shared hosting companies block one account from being able to see the other accounts on the same server. If you are concerned about your hosting company, then you should either ask them about this issue or move to a dedicated or virtual hosting server.)

The last value for the access attribute is remote. This is actually how you create a number of “cool power” uses of the CFC. There is a technology on the Web called web services. Setting the CFC to remote allows access to the CFC as a web service. You can also connect to this CFC through Flash applications, Flex, or AIR, using the remote access value. This method also allows the CFC to respond to AJAX calls. Now, we will learn to use more of the local power features.

Web forms introduction

Here, we will discuss web forms along with CFCs.

Let us view our web form page. Web forms are the same in ColdFusion as they are in any other HTML scenario. You might even note that there is very little use for web forms until you have a server-side technology such as ColdFusion. This is because when the form is posted, you need some sort of program to handle the data posted back to the server.

<!--- Example: 3_1.cfm --->
<!--- Processing --->
<!--- Content --->
<form action="3_1.cfm" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" name="name" id="idName" value="" /></td>
</tr>
<tr>
<td>Description:</td>
<td><input type="text" name="description" id="idDescription"
value="" /></td>
</tr>
<tr>
<td>Price:</td>
<td><input type="text" name="price" id="idPrice"
value="" /></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" name="submit" value="submit" /></td>
</tr>
</table>
</form>

First, notice that all of the information on the page is in the content section. Anything that goes from the server to the browser is considered as content. You can fll in and submit the form, and you will observe that all of the form fields get cleared out. This is because this form posts back to the same page. Self-posting forms are a valid method of handling page fow on websites. The reason why nothing seems to be happening is because the server is not doing anything with the data being sent back from the browser. Let us now add <cfdump var=”#form#”/> to the bottom of the content, below the form tag, and observe what we get when we post the form:

Now we see another common structure in ColdFusion. It is known as the form structure. There are two types of common structures that send data to the server. The first one is called get and the second one is called post. If you see the code, you will notice that the method of the form is post. The form post setting is the same as coding with the form variable in ColdFusion.

You should also observe that there is one extra field in the form structure that is not shown in the URL structure variable. It is the FIELDNAMES variable. It returns a simple list of the field names that were returned with the form. Let us edit the code and change the form tag attribute to get. Then, refresh the page and click on the submit button:

From the previous screenshot, it is evident that the browser looks at the get or post value of the form, and sends a get or post back to the server. Post is a “form method” belonging to the past and this is why ColdFusion translates posted variables to the form structure. Now change the dump tag to “URL” and observe the results. Fill out the form and submit it again with the new change. This displays the values in our structure as we would expect. This means you can either send URL-type data back to the server, or form-type data with forms.

The advantage of sending form data is that form data can handle a larger volume of data being sent back to the server as compared to a get or URL request. Also, it is worth noting that this style of return prevents the form field values from being exposed in the URL. They can still be accessed, but are just not visible in the URL any more. So the method of choice for forms is post. Change both the method of the form attribute and the value of the cfdump var to form again.

The Description box is not ideal for entering product descriptions. So, we are going to use a text area in its place. Use the following code to accommodate a text area box. You can change the size of form’s objects using attributes and styles:

<tr>
<td>Description:</td>
<td>
<textArea name="description" id="idDescription"></textArea>
</td>
</tr>

Here, we see our form looking different. If you fill up the description with more content than the box can hold, it shows the scroll bars appropriately.

Managing our product data

Currently, we have a form that can be used for two purposes. It can be used to enter a new product as well as to edit existing ones. We are going to reuse this form. Reuse is the fastest path to make things easier. However, we must not think that it is the only way to do things. What we should think is that not reusing something requires a reason for doing it differently.

In order to edit an existing product, we will have to create a page that shows the existing product records. Let us create the page:

<!--- Example: product_list.cfm --->
<!--- Processing --->
<cfscript>
objProduct = createObject("component","product").init(dsn="cfb");
rsProducts = objProduct.getRecordset();
</cfscript>
<!--- Content --->
<h3>Select a product to edit.</h3>
<ul>
<cfoutput query="rsProducts">
<li>
<a href="product_edit.cfm?id=#rsProducts.id#">#rsProducts.name#
</li>
</cfoutput>
</ul>

There is no new code here. This is the browser view that we get when we run this page. Here, we will post our edit page. Before you run the code, take the code from 3_1.cfm that we wrote at the beginning of the article and save a copy as product_edit.cfm to make the page work correctly when someone clicks on any of the products:

Now, we will click on a product. Let us manage the Watermelon Plant for now and observe what happens on the next page:

This is our edit page, and we will modify it so that it can get the data when we click through from our list page.

Getting data to our edit page

The current page looks similar to the page where we put the form. To get the data from our database onto the page, we need to do a few things here. First, let us change the action of the form tag to product_edit.cfm. We can modify the processing section of the page frst, which will make things simpler. Add the following code to your product_edit.cfm page:

<!--- Processing --->
<cfparam name="url.id" default="0">
<cfscript>
objProduct = createObject("component","product").init(dsn="cfb");
objProduct.load(url.id);
</cfscript>

We need the default value set so that we do not receive an error message if the page is called without an id. After we set our default, we will see that we have created an object from our CFC object class. This time, we are passing the Data Source Name dsn into the object through the constructor method. This makes our code more portable, and ready for reuse. Once we have an instance, we set the current record using the load method and passing the id of the data record to the method. Let us look at the minor changes that we will make to the content section. We will add the values of the object’s protected attributes.

<!--- Content --->
<cfoutput>
<form action="product_edit.cfm" method="post">
<table>
<tr>
<td>Name:</td>
<td>
<input type="text" name="name" id="idName"
value="#objProduct.get('name')#" />
</td>
</tr>
<tr>
<td>Description:</td>
<td>
<textArea name="description" id="idDescription">
#objProduct.get('description')#</textArea>
</td>
</tr>
<tr>
<td>Price:</td>
<td>
<input type="text" name="price" id="idPrice"
value="#objProduct.get('price')#" />
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<input type="submit" name="submit" value="submit" />
</td>
</tr>
</table>
</form>
</cfoutput>

Now, we will refresh the form and see how the results differ:

Doesn’t this look better? We can go back to the list page and retrieve an existing product from the edit form.

If we submit back the same form, browsers tend to empty out the form. It should not do that, but the form is not posting the ID of the record back to the server. This can lead to a problem because, if we do not send the ID of the record back, the database will have no idea as to which record’s details should be changed. Let us solve these issues first, and then we will learn to use a new tag called the <cfinclude> tag along the way.

The first problem that we are going to solve is where we are calling the page with the ID value in the URL structure; then, if we post the page we will be calling the page with the ID in the form structure. We are going to use a technique that has been widely used for years in the ColdFusion community. We are going to combine the two scopes into a new common structure. We will create a structure called attributes. First we will check if it exists. If it does not, then we will create the structure. After that, we will merge the URL structure, and then the FORM structure into the attributes structure. We will put that code in a common page called request_attributes.cfm, so we can include it on any page we want, reusing the code. Do remember that the form and URL scope always exist.

<!--- request_attributes.cfm --->
<cfscript>
if(NOT isDefined("attributes"))
{
attributes = structNew();
}
structAppend(attributes,url);
structAppend(attributes,form);
</cfscript>

Let us modify our edit page in order to take care of a couple of issues. We need to include the script that we have just created. We will modify the processing section of our edit page as highlighted here:

<!--- Processing --->
<cfinclude template="request_attributes.cfm">
<cfparam name="attributes.id" default="0">
<cfscript>
objProduct = createObject("component","product").init(dsn="cfb");
objProduct.load(attributes.id);
</cfscript>

There is only one more thing we need now: We need our form to store the id value of the record that is being managed. We could just put it in a textbox like the other fields, but the user does not need to know that information. Let us use a hidden input field and add it after our form tag:

<!--- Content --->
<cfoutput>
<form action="product_edit.cfm" method="post">
<input type="hidden" name="id" value="#objProduct.get('id')#">

Refresh the screen, and it will work when we use the form, or when we choose an item from the product list page. We have now created our edit/add page.

LEAVE A REPLY

Please enter your comment!
Please enter your name here