Important alert: (current site time 6/19/2013 1:25:08 AM EDT)
 

article

List Drive Dynamic Fields

Email
Submitted on: 8/27/2004 9:53:36 AM
By: Jerry Barnes  
Level: Beginner
User Rating: Unrated
Compatibility: Cold Fusion 4.5, Pre Cold Fusion 4.5, Cold Fusion 5, Cold Fusion MX
Views: 12442
 
     This article demonstrates how to create dynamic HTML controls such as checkboxes, select boxes, and radio groups without a database.

This article has accompanying files
 
 
Terms of Agreement:   
By using this article, you agree to the following terms...   
  1. You may use this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
  3. You may link to this article from another website, but ONLY if it is not wrapped in a frame. 
  4. You will abide by any additional copyright restrictions which the author may have placed in the article or article's description.
				
List Driven Dynamic Fields
Create Dynamic Checkboxes, Select Boxes, and Radio Groups Without Using A Database

When I was a rookie Coldfusion programmer, I was excited about the ability of Coldfusion to dynamically drive select boxes, radio buttons, and check boxes. I used every opportunity that presented itself to create tables which held descriptions, values, variable names, and such. Then I would create a query, loop over it, and create my controls. I believe my rationale made sense. It would be easier to add another record to the table than it would be to drag up the template and create a new input object.

Well, time has a way of demonstrating the effectivness of ideas. The idea of table driving everthing became burdonsome. Any time I wanted to add a new item to a form, I had to open the database, find the table, enter the record, and make sure I had the correct sort-order entered (every list had to have a sort-order column in order to allow for future addition placement). If I wanted to change a description, value, etc., I had to open up the database, find the table, find the record, then make the edit. Then, I had the repeat the process two more times for the practice site and the live site.I could have written interfaces for all of these tables as well, but I think we all know how tedious that can become. Finally, my database was getting littered with lots of little tables whose purposes were easy to forget (a discerning reader might ask why I didn't just create one table to rule them all; I tried, but the number of times that a set of controls needed a special field kept making table upkeep frustrating).

After about a year and a half of table driving everything, I got tired of the process. Fortunately, a new solution dawned upon me. Others may have used this idea before, but I had never seen it. I spend a lot of time scouring the net for good ideas, too. When I shared the idea at a local PUG meeting, no one had ever used it before and many seemed intrigued by the idea. That was several years ago. I finally got the motivation to post the idea.

The idea came to me when I was working with some lists. I can't remember what I was working on specifically, but an epiphany dropped like a bombshell on my head. What about list within lists? The only problem I could see at first was a lack of delimiters. However, there are plenty of characters that most people don't use. In fact, special characters can be used (you can use #chr(8)# as a delimter if you so choose). If you look at the following list, you will see what I mean when I say a list within a list.

<cfscript>
lst01 = "1^Is it hard for you to walk^PF01|";
lst01 = lst01 & "2^Is it hard for you to run^PF01|";
lst01 = lst01 & "3^Is it hard for you to play sports or exercise^PF01|";
lst01 = lst01 & "4^Is it hard for you pick up big things^PF01|";
<cfscript>

You can break the list down into parts. The first line contains: 1^Is it hard for you to walk^PF01|. In this case, "|" is the delimter for the main list while "^" is the delimiter for the list within a list. The inner list contains three parts: value, description, and variable name. The main list contains four items. A programmer can use code similar to the following to loop over the whole list and assemble a set of check boxes.

<cfloop list="#lst01#" index="i" delimiters="|">
<cfscript>
intNum = listgetat(i,1,"^");
strDescript = listgetat(i,2,"^");
strVar = listgetat(i,3,"^");
strVal = evaluate("qryTest.#strVar#");
</cfscript>
<input type="Checkbox"
 	 name="#strVar#"
		 value="#intNum#"
		 <cfif intNum is strVal>checked</cfif>>#strDescript#<br>
</cfloop> 

The code is not revolutionary. It is pretty straight forward. The only thing remotely tricky is the evaluate function. It is necessary in order to get the values form the query that is returning data to a form. For formatting purposes, a programmer could throw some TD's and TR's in to make uniform alignment.

Now, the process has been explained. Is it really any better than table driving dynamic fields? I think so. Here's why:

  • The code is more encapsulated. A programmer does not have to go to a database to make change or additions. All changes are effective on remote sites as soon as the edited page is pushed to its new location. This makes debugging easier as well.
  • It is easy to change the list. If an item is not needed, drop // in front of its line in the cfscript tag. It becormes disabled. No needed for a "disabled" field in a table (you should never delete a definition record from a table because of data that might be stored in other tables). Want to add an item, just start typing.
  • The code can be reusable. Drop the definition list in a template of definitions. Use cfinclude to bring in the definitions when needed (this doesn't really break the encapsulation thing because the definition template should be right there on your server with the template using it).
  • The template is reusable in other projects. Save the page in another project and your done. No need to create tables or definitions.
  • It's easy for other programmers to follow your code. Everything they need is right there in front of them. It also makes it easier on the original programmer when he or she hasn't seen the code in 6 months and a "rush" change needs to be made.

I did not spend a lot of time thinking about negatives for this idea. I like this method and plan on using it for a while so I just wasn't interested in the other side of the coin. I am sure people can find numerous negatives. One that comes to mind would be returning data to another form. For example, the database returns a value of 1 for a question (I am not talking about the descriptions table but the forms table). Programmers need to match this 1 up with a specific description sometimes for various reason (reports, etc.). An inner join can be used if the controls are table driven. Speed may be an issue. I have never benchmarked this process. I have heard that arrays run faster in Coldfusion MX. I suppose this code could be converted rather easily to an array format. I just didn't want to deal with array lengths and loops and at the time, I am fortunate enough to work on low traffic sites..

The following is a code example. A reader can cut and paste this in a template, save, and it should run right away.

 

<!--- Make a list of data for a query. --->
<cfscript>
lstValues="1,2";
</cfscript>
<!--- Convert the list to a query in order to make the example more realistic. --->
<cfset qryTest = QueryNew("PF01,EF01")>
<cfset temp = QueryAddRow(qryTest)>
<cfset Temp = QuerySetCell(qryTest, "PF01", listgetat(lstValues,1))>
<cfset Temp = QuerySetCell(qryTest, "EF01", listgetat(lstValues,2))>
<!--- List to generate check boxes --->
<cfscript>
lst01 = "1^Is it hard for you to walk^PF01|";
lst01 = lst01 & "2^Is it hard for you to run^PF01|";
lst01 = lst01 & "3^Is it hard for you to play sports or exercise^PF01|";
lst01 = lst01 & "4^Is it hard for you pick up big things^PF01|";
lst02 = "1^Do you feel scared^EF01|";
lst02 = lst02 & "2^Do you feel sad^EF01|";
lst02 = lst02 & "3^Do you feel mad^EF01|";
lst02 = lst02 & "4^Do you have trouble sleeping^EF01|";
</cfscript>
<cfoutput>
<div align="center">
<form name="frmTest">
<table>
<tr>
 <td>Question 1</td>
</tr>
<tr valign="top">
 <td>
 <cfloop list="#lst01#" index="i" delimiters="|"> 
<cfscript>
intNum = listgetat(i,1,"^");
strDescript = listgetat(i,2,"^");
strVar = listgetat(i,3,"^");
strVal = evaluate("qryTest.#strVar#");
</cfscript>
<input type="Checkbox" 
name="#strVar#" 
value="#intNum#"
<cfif intNum is strVal>checked</cfif>>#strDescript#<br>
 </cfloop> 
 </td>
</tr>
<tr>
 <td>&nbsp;</td>
</tr>
<tr>
 <td>Question 2</td>
</tr>
<tr valign="top">
 <td>
 <cfloop list="#lst02#" index="i" delimiters="|">
<cfscript>
intNum = listgetat(i,1,"^");
strDescript = listgetat(i,2,"^");
strVar = listgetat(i,3,"^");
strVal = evaluate("qryTest.#strVar#");
</cfscript>
<input type="Checkbox" 
name="#strVar#" 
value="#intNum#"
<cfif intNum is strVal>checked</cfif>>#strDescript#<br>
 </cfloop>
 </td>
</tr>
</table>
</form>
</div>
</cfoutput>

 

Now, if you have stuck with this so far and you examined the code above carefully, you may be asking yourself why I included the variable name in the inner list. It would not have been a big deal to hard code it in the example above. I will answer this question with an example:

 

<cfset lstMaster = "Question 1~lst01|Question 2~lst02|>

 

Hopefully, you read that and a light went off. If not, don't worry about it. You'll get it sooner or later. I did not expand the writing to cover select boxes or radio button groups. The idea is easily transferable to other controls without much work.


Disclaimer: The terms "Best Practice" and "Coding Standards" are subjective. This means that what is a "best practice" or a "standard" for one may be a pox for another. I am in no way claiming that anyone should use the above code. It is just an example of something that I find useful.

As far as I know, this work is original. I have not intentionally copied anyone's work.

winzip iconDownload article

Note: Due to the size or complexity of this submission, the author has submitted it as a .zip file to shorten your download time. Afterdownloading it, you will need a program like Winzip to decompress it.Virus note:All files are scanned once-a-day by Planet Source Code for viruses, but new viruses come out every day, so no prevention program can catch 100% of them. For your own safety, please:
  1. Re-scan downloaded files using your personal virus checker before using it.
  2. NEVER, EVER run compiled files (.exe's, .ocx's, .dll's etc.)--only run source code.

If you don't have a virus scanner, you can get one at many places on the net including:McAfee.com

 
Terms of Agreement:   
By using this article, you agree to the following terms...   
  1. You may use this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
  3. You may link to this article from another website, but ONLY if it is not wrapped in a frame. 
  4. You will abide by any additional copyright restrictions which the author may have placed in the article or article's description.


Other 3 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Beginner category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments


 There are no comments on this submission.
 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.