As a follow-up from my earlier posting on tabbed dialog boxes using ColdFusion 8's new cflayout and cflayoutarea tags, I'll explain how you can also use those same tags to create dialog boxes with expandable/collapsible trees or icon lists in the left-hand pane and forms in the right-hand pane. These kinds of interfaces will be readily recognizable by users since they're almost exactly the same as you'd find in a desktop application.
What we want to end up with is a window containing a hierarchical tree in a left-hand pane and a form area in the right-hand pane, with "Save", "Cancel", and "Apply" buttons at the bottom:

To create this layout, we're going to use cflayout and cflayoutarea to place the tree on the left, the form on the right, and the buttons on the bottom; we're going to use the cftree and cftreeitem tags to create the tree; and we're going to use absolute positioning and the visibility style attribute to control which subset of the form fields appear in the right-hand pane. So, here's the code:
<style type="text/css">
body {font: 11px verdana, arial, sans-serif; padding: 20px;}
input[type="submit"] {width: 80px;}
.ytab {padding: 10px;}
</style>
<p><strong>Preferences</strong></p>
<cfform action="preferences.cfm" method="post">
<cflayout type="vbox">
<cflayoutarea><!--- The top row --->
<cflayout type="hbox">
<cflayoutarea style="width: 120px; height: 250px; margin-right: 20px; border: 2px inset;"><!--- The left column --->
<cftree name="nav" format="html">
<cftreeitem value="General" />
<cftreeitem value="Sub-item1" parent="General" href="javascript:showArea('general');" />
<cftreeitem value="Sub-item2" parent="General" href="javascript:showArea('general');"/>
<cftreeitem value="Appearance" expand="no" />
<cftreeitem value="Sub-item1" parent="Appearance" href="javascript:showArea('appearance');" />
<cftreeitem value="Sub-item2" parent="Appearance" href="javascript:showArea('appearance');"/>
<cftreeitem value="Security" expand="no" />
<cftreeitem value="Sub-item1" parent="Security" href="javascript:showArea('security');" />
<cftreeitem value="Sub-item2" parent="Security" href="javascript:showArea('security');"/>
</cftree>
</cflayoutarea>
<cflayoutarea>
<cflayout type="vbox">
<cflayoutarea name="general" style="position: absolute;">
<p>Field 1: <input type="text" name="" /></p>
<p>Field 2: <input type="text" name="" /></p>
<p>Field 3: <input type="text" name="" /></p>
</cflayoutarea>
<cflayoutarea name="appearance" style="position: absolute; visibility: hidden;">
<p>Field 4: <input type="text" name="" /></p>
<p>Field 5: <input type="text" name="" /></p>
<p>Field 6: <input type="text" name="" /></p>
</cflayoutarea>
<cflayoutarea name="security" style="position: absolute; visibility: hidden;">
<p>Field 7: <input type="text" name="" /></p>
<p>Field 8: <input type="text" name="" /></p>
<p>Field 9: <input type="text" name="" /></p>
</cflayoutarea>
</cflayout>
</cflayoutarea>
</cflayout>
</cflayoutarea><!--- The bottom row --->
<cflayoutarea align="right" style="margin-top: 10px;">
<input type="submit" name="save" value="OK" />
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="apply" value="Apply" />
</cflayoutarea>
</cflayout>
</cfform>
Note that the tree's sub-items have JavaScript code specified in the href attribute. This code calls a custom function to show or hide each form area as needed:
<script language="JavaScript">
function showArea(area) {
// Hide all areas
document.getElementById('general').style.visibility = 'hidden';
document.getElementById('appearance').style.visibility = 'hidden';
document.getElementById('security').style.visibility = 'hidden';
// Show the area being called
document.getElementById(area).style.visibility = 'visible';
}
</script>
Now what if you wanted to use icons for navigation instead of a tree structure, just as Firefox and Thunderbird do?

That's a snap as well (and note that you could just as easily have the icons go across the top of the dialog box just by modifying your cflayoutarea tags). Just replace the <cftree> tags with a much more simple set of HTML specifying center-aligned images, like so:
<script language="JavaScript">
function showArea(area) {
// Hide all areas
document.getElementById('general').style.visibility = 'hidden';
document.getElementById('appearance').style.visibility = 'hidden';
document.getElementById('security').style.visibility = 'hidden';
// Show the area being called
document.getElementById(area).style.visibility = 'visible';
}
</script>
<style type="text/css">
body {font: 11px verdana, arial, sans-serif; padding: 20px;}
input[type="submit"] {width: 80px;}
</style>
<p><strong>Preferences</strong></p>
<cfform action="preferences.cfm" method="post">
<cflayout type="vbox">
<cflayoutarea><!--- The top row --->
<cflayout type="hbox">
<cflayoutarea style="width: 120px; height: 250px; margin-right: 20px; border: 2px inset;"><!--- The left column --->
<div style="text-align: center;">
<a href="javascript:showArea('general');"><img src="general.gif" border="0" alt="General" /></a><br />
General<br />
<a href="javascript:showArea('appearance');"><img src="appearance.gif" border="0" alt="Appearance" /></a><br />
Appearance<br />
<a href="javascript:showArea('security');"><img src="security.gif" border="0" alt="Security" /></a><br />
Security<br />
</div>
</cflayoutarea>
<cflayoutarea>
<cflayout type="vbox">
<cflayoutarea name="general" style="position: absolute;">
<p>Field 1: <input type="text" name="" /></p>
<p>Field 2: <input type="text" name="" /></p>
<p>Field 3: <input type="text" name="" /></p>
</cflayoutarea>
<cflayoutarea name="appearance" style="position: absolute; visibility: hidden;">
<p>Field 4: <input type="text" name="" /></p>
<p>Field 5: <input type="text" name="" /></p>
<p>Field 6: <input type="text" name="" /></p>
</cflayoutarea>
<cflayoutarea name="security" style="position: absolute; visibility: hidden;">
<p>Field 7: <input type="text" name="" /></p>
<p>Field 8: <input type="text" name="" /></p>
<p>Field 9: <input type="text" name="" /></p>
</cflayoutarea>
</cflayout>
</cflayoutarea>
</cflayout>
</cflayoutarea><!--- The bottom row --->
<cflayoutarea align="right" style="margin-top: 10px;">
<input type="submit" name="save" value="OK" />
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="apply" value="Apply" />
</cflayoutarea>
</cflayout>
</cfform>
Handling the form submission for a dialog box like this, as explained in the previous post on tabbed dialog boxes, is pretty simple. Put this code at the top of your dialog page:
<cfif IsDefined("FORM.save") or IsDefined("FORM.apply")>
<!--- Save the data to persistent storage --->
</cfif>
<cfif IsDefined("FORM.save") or IsDefined("FORM.cancel")>
<!--- Close this popup window --->
<script language="JavaScript">
opener.focus();
self.close();
</script>
</cfif>
If the user clicks on the "Save" button or the "Apply" button, the form data is saved (to persistent storage, such as session variables or a database); also, if the "Cancel" button or the "Save" button is clicked, the popup window containing the dialog box will close and the user will be returned to the main browser window. If the user clicks on the "Apply" button, the dialog box stays around-- but, according to the needs of your application, you may want to either refresh the main browser or perhaps re-select the area which was selected before the form was submitted so that you retain state for the user (otherwise, because we're refreshing the page in this example, the user will see the first area become selected). You could also avoid the page refresh by submitting the form with AJAX. I'll leave form reselection and/or AJAX as an exercise for the reader.

Comments (2)
August 7, 2007
14:28PM | #
nit picker :)
the first block of code is missing the closing cfform for anyone who might be a paster :)
great walktrhough though. Thank you, I learned a lot on cflayout!
August 7, 2007
15:01PM | #
@Dana: Thanks for catching the omission in my code, it's been fixed!