ColdFusion in Context: Check More

This tip lets you make checkboxes more useful while saving database hits.

Beef up Checkboxes

Checkboxes are the logical tool for yes/no tasks, but sometimes they need a little help. Suppose your user is working with many rows of yes/no options at a time. Perhaps the page lists every task and lets this user which task this account or role can perform. (Hopefully it's a long list.) This seems straightforward, but there's a catch coming. If the box isn't checked, the field isn't passed at all. You don't get "off", you get nothing.

Checkboxes are like radio buttons in one sense. They can be treated as part of a group. With radio buttons in one group, you get one of many values for a single name. Donald Gilliland noticed that you can pair a checkbox with a hidden field of the same name and always get at least one value. For example, if you set the hidden field to yes, select the box, and the user leaves the box of the same name checked, you get "on,yes" or the equivalent. If the user unchecks the box, you get simply "yea". Think about it. You can loop the existing form fields and not miss anything if you interpret correctly what you get.

Query Once; Read Twice

Suppose you did an involved query from many tables to get the checkboxes set in the first place, remembering the idea that you'd like to set user or role permissions for everything your site can do. When the user submits the form, you'd like to know which ones changed (so you can update the database) without having to do that involved query again. But how?

Try pairing the two ideas. Set the hidden field to something like "yea" for yes or "nay" for no and check or uncheck the box to match. When you read the field - it will always be passed - if it contains both "yea" and "on" (or just "nay" by itself), then nothing has changed. If you get just "yea" by itself meaning the user has unchecked the box, or you get "on" and "nay" meaning the user has checked an unchecked box, you know the state has changed and that you need to update things. Let's try it out.

Prepare to See the Values

Put this one-liner in MyPost.cfm. For this demo, a way to inspect the form values that make it to the action page is good enough. So, use cfdump.

<cfdump var="#form#">

Get the Values and Build the Form

Put this code in MyForm.cfm. Since you already know how to do queries, let's build a structure named Perm (for permission) from which to fill the checkboxes.

<cfscript>
Perm=structNew();
Perm.CreateHQ=0;
Perm.UpdateHQ=1;
Perm.DeleteHQ=0;
Perm.CreateDiv=1;
Perm.UpdateDiv=1;
Perm.DeleteDiv=0;
Perm.CreateOffice=1;
Perm.UpdateOffice=1;
Perm.DeleteOffice=1;
</cfscript>

Open a form and loop the list of structure keys in a manner similar to the way you'd loop a query to dynamically build a form having many rows. Treat Key as the name of the "column" and use array notation to get its value.

You want the word "selected" to be an attribute of the checkbox if it should start off selected. A quick way to do this is to use the iif function, surrounded by pound signs. Because the iif() function will try to evaluate its alternatives, you'll usually use the de() function to delay evaluation as shown here when you use it. Let it repeat for all inputs, add a submit button, and close the form.

<form name="SetAccount" method="post" action="MyPost.cfm">
<cfloop list="#structKeyList(Perm)#" index="Key">
<cfoutput>

#Key#<input type="checkbox" name="#Key#" value="#Perm[Key]#"
#iif(Perm[Key],de("checked"),de(""))#><br>

<input type="hidden" name="#Key#"
value="#iif(Perm[Key],de('yea'),de('nay'))#">
</cfoutput>
</cfloop>
<input type="submit" name="doit" value="Submit">
</form>

Admire the Result

Browse MyForm.cfm, alter the inputs, and look at the values that reach MyPost.cfm. If the value is "on,yea" or simply "nay", the value hasn't changed. If the value is "on,nay" (turned off to on) or simply "yea" (turned on to off), update the database accordingly. Play with this concept and show us what you've learned. =Marty=