Ask a Jedi: cfdiv, cfform, cflayout and selecting tabs - also a new bug?

This post is more than 2 years old.

Patrick asks:

Quick question (i think). I have this CFDIV with a form on it. When I submit this form I want it to go to another page (within the cfdiv) that has a cf tab layout on it, and based on whatever they select on the form I would like that tab to be selected when hitting the cf tab layout on the new page after they submit the form. Any ideas on how I could accomplish this, my attempts have failed. Thanks.

Let's break this down a bit.

First off, when inside a cfdiv (or pod, window, layoutarea), you can automatically keep the form post inside the container by using cfform. So consider these two simple files. First, my root test file:

<cfajaximport tags="cfform,cflayout-tab">

<h2>Headers for the Win</h2>

<cfdiv bind="url:test3.cfm" />

<h2>Footers for the Win</h2>

And then test3.cfm:

<cfform action="test2.cfm" method="post"> <cfinput type="submit" name="doit1" value="Do One"> <cfinput type="submit" name="doit2" value="Do Two"> <cfinput type="submit" name="doit3" value="Do Three"> </cfform>

Nothing too complex here. (I'll explain the button names in a sec.) This will load a page with a div where CF's Ajax code will automatically load in test2.cfm. Because I used cfform, the post will stay within the div context. Now I need to build a page that creates tabs and automatically selects the right one. This too is rather trivial.

<cfset t1Selected = false> <cfset t2Selected = false> <cfset t3Selected = false>

<cfif structKeyExists(form, "doit1")> <cfset t1Selected = true> <cfelseif structKeyExists(form, "doit2")> <cfset t2Selected = true> <cfelse> <cfset t3Selected = true> </cfif>

<cflayout type="tab"> <cflayoutarea title="Tab1" selected="#t1Selected#" /> <cflayoutarea title="Tab2" selected="#t2Selected#" /> <cflayoutarea title="Tab3" selected="#t3Selected#" /> </cflayout>

As you can see, I simply set state values for each tab to false and then check my form scope to see which value was passed. I say trivial, but when working on this I ran into two odd bugs.

First off, my form initially had buttons with a name of action. When I did that, the form post failed due to some odd JavaScript error. It seems as if you cannot use a form field named ACTION within a form that will be 'ajax posted' within cfform. So I changed all 3 buttons to "doit". Since the value was different, I should get form.doit equal to whatever button you push, right? Wrong. No matter what I pushed, the value was equal to all three values appended together in a list. Hence the switch to doit1, doit2, doit3. I assume again that this is just a quirk of CF's automatic "keep it inside" logic for cfform within containers.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Nick posted on 1/10/2009 at 4:39 AM

Do it, Doug!

This is actually a pretty handly little tip. I love "Secretly" reserved words.

Comment 2 by Jason Fisher posted on 1/10/2009 at 8:58 AM

Ray, isn't the observed behavior probably just because every form already has an ACTION element? Would think that's not a very secret reserved word, actually, since it's an inherent attribute of the HTML FORM tag.

Just a thought.

Comment 3 by Raymond Camden posted on 1/10/2009 at 9:01 AM

The form tag has an an action attribute, but that has nothing to do with the data posted in the form scope itself. For example, this form post:

<cfdump var="#form#">

<form action="test4.cfm" method="post">
<input type="text" name="name" />
<input type="submit" name="action" value="one"/>
<input type="submit" name="action" value="two"/>
</form>

Works just fine in a page by itself (no cfdivs involved).

Comment 4 by Jason Fisher posted on 1/10/2009 at 5:43 PM

Good point, Ray, just hadn't time to test that before I posted. In JavaScript, though, you can certainly change the form's action attribute:

var frm = document.forms["myForm"];

if (someBehavior) {
frm.action = "changeMyTargetHandler.cfm";
}

Guess that's where the cfdiv is coming in to play, on the JavaScript side of things, do you think?

Comment 5 by Raymond Camden posted on 1/10/2009 at 6:32 PM

Certain - JS can change the action of the form and form data itself. My main point is that form.action != form.data. (imho)

As to what cfdiv is doing - not sure. I'm thinking it must not separate the form data from the form ... "info" (as in the action).

Comment 6 by Adam Cameron posted on 1/10/2009 at 7:14 PM

Hi Ray
I await with bated breath for these bugs to be registered with the CF9 programme...

--
Adam

Comment 7 by Raymond Camden posted on 1/10/2009 at 7:19 PM

Ahem - The #1 rule of the Adobe beta programs is that there is no Adobe beta program.... ;)

Comment 8 by Adam Cameron posted on 1/10/2009 at 7:54 PM

What, so this - http://labs.adobe.com/wiki/... - doesn't exist? It's a bit disingenuous for Adobe to make it public knowledge then, eh?

(NB: I note with derision the .PHP extension!)

I think it's less a case of "the rules of Fight Club" and more a case of "what goes on tour stays on tour".

Anyway, all I meant is that if someone happened to discover bugs like these, and if they happened to be on any relevant alpha/beta programme (and whether or not they are: I couldn't say), then I would expect that perhaps they should extract-digit and get an issue raised for them. Maybe people might want to vote for it (although I could not confirm that). If - like - there was the capability to vote... which... err... wait... what's that black helicopter doing hovering outside my window??!

;-)

Anyway: chop-chop, old son.

--
Adam

Comment 9 by Raymond Camden posted on 1/10/2009 at 7:56 PM

Heh, I was just teasing ya know. If there is such a way to report bugs then maybe I'll do so....

Comment 10 by Jason Fisher posted on 1/10/2009 at 10:27 PM

@Ray,

Yes, you're definitely right that form.action != form.data. It's clean in HTML and it's clean in CF's form scope, but I think it just struck me when you first posted because of the lack of clarity that JS adds to the whole mix. To wit, the following scenario:

<form action="test.cfm" id="testFrm" method="post">
Activity:
<input type="Radio" name="action" value="run" />run
<input type="Radio" name="action" value="walk" />walk
<br />
Description:
<input type="Text" name="description" value="slowly" />
<br />
<input type="Button" value="take action" onclick="play(this.form);" />
</form>

If I use JS to work with the form elements, I could do the following to refer to my text field:

var desc = document.forms.testFrm.elements["description"];

but I could also do this:

var desc = document.forms.testFrm.description;

But in this form, there's now an action parameter of the form and another action element of the elements collection. It turns out that both of these will get to the form element, so I guess I no longer have access to the form action ("test.cfm") within JS once I've added an element named 'action'.

var action = document.forms.testFrm.action;

gives me the same NodeList object as this:

var action = document.forms.testFrm.elements["action"];

Without the radio buttons being named 'action', document.forms.testFrm.action would return "test.cfm". Fascinating.

Comment 11 by Raymond Camden posted on 1/10/2009 at 10:42 PM

Digging with jQuery, it looks like you can get the form tag action by using f.attributes (where F == the form object). The attributes array represented everything I had in my form tag.

So there should be no problem differentiating between the ACTION of the form tag and any elements named action within the form itself.

Comment 12 by Jason Fisher posted on 1/10/2009 at 10:48 PM

Right, apparently just issues with the way cfdiv is interoperating with the form objects.

Comment 13 by Raymond Camden posted on 1/10/2009 at 10:49 PM

So its all Adobe's fault. That's it - I'm switching to PHP and Classic ASP! ;)

Comment 14 by Jason Fisher posted on 1/10/2009 at 10:58 PM

ROFL ... no, not the Dark Side(tm)!!

Comment 15 by Bob posted on 5/13/2009 at 12:55 PM

Ray ,
i used your example , and it works fine ...
however when i change the form to flash format
<cfform action="test2.cfm" method="post" format="flash">

errors pop up and couldn't find a solution for it ,
why !? can you help ?

Comment 16 by Raymond Camden posted on 5/13/2009 at 3:33 PM

Flash Forms are definitely not going to work. That's about the best I can say. I'd recommend moving away from FF.

Comment 17 by miked posted on 11/11/2009 at 3:49 AM

Note too that if you need to have your form submission "break out" of the cfdiv, you must use <form> instead of <cfform>. I have a page with a select and a cfdiv. The select chooses a document type and the cfdiv displays the available documents for that type. In the cfdiv, a form with check-boxes lets you select which of the docs you want to bundle for printing. Submitting the form opens a page that does a cfpdf merge with the selected docs. If I use a <cfform> in the cfdiv page, it stays in the cfdiv context and displays binary junk. If I use a <form>, it allows for save/open of the generated pdf. That only took me a day to figure out ;>)

Comment 18 by Charlie Stell posted on 12/11/2009 at 4:09 AM

Your post here probably saved me hours of pulling my hair out...

Comment 19 by Dan posted on 1/5/2010 at 3:36 AM

I know this post is a little old now, but I just came across it and used it, adapted it, and really liked it. But, when I went to extend if with cfform, it fails. Well, it works unexpectedly.
When clicking "Do it", it opens up another set of 3 tabs within the tab I started. So I am in tab 3, enter data... and click Do It 2. On load, I am still in tab 3, and the content in tab 3 is then the same 3 tabs nested there, with the 2nd tab selected.
When it is <form> it work fine, when <cfform> this crazy result. The issue is I have some <cfselects> I want to use so need <cfform> Anything I can do?

Comment 20 by Dan posted on 1/5/2010 at 4:24 AM

I should add, I am trying to make the form IN the tab. That is when it works with <form> and not <cfform>.

<cflayout type="tab">
<cflayoutarea title="Tab1" selected="#t1Selected#"></cflayoutarea>
<cflayoutarea title="Tab2" selected="#t2Selected#" >
Show <cfoutput>
<cfif structKeyExists(form,"something")>
#form.something#
</cfif>
</cfoutput>
</cflayoutarea>
<cflayoutarea title="Tab3" selected="#t3Selected#" >
<cfform name="testForm" action="Test2.cfm" method="post">
<input type="text" name="something">
<input type="submit" name="doit1" value="Do One">
<input type="submit" name="doit2" value="Do Two" >
<input type="submit" name="doit3" value="Do Three">
</cfform>
</cflayoutarea>
</cflayout>

I want to enter info on one tab, click submit, and process and display results on the next tab.

Comment 21 by Raymond Camden posted on 1/5/2010 at 4:26 AM

cfform inside a cfdiv/cfwindow/cflayout automatically switches to an Ajax-based post, so you lose some control over the submission unless you want to write custom code to handle it.

Comment 22 by Antonio posted on 6/17/2010 at 5:51 PM

Guys, im going mad:

<cfloop query="dettaglio">

<cfquery name="dett_piazz" datasource="intranet">
select * from temp_#replacenocase(url.n_tagtl,"-","","ALL")# where n_tagtl='#url.n_tagtl#' and tipotagliotl='#piazzatura#'
</cfquery>
<cfquery name="nome_piaz" datasource="intranet">
select lav_descrizione from tab_lavorazioni where id_lavorazione='#piazzatura#'
</cfquery>

<table style="width: 100%" >

<thead>
<th><td colspan=6><strong style="color:red">Lavorazione: <cfoutput>#piazzatura# #nome_piaz.lav_descrizione#</cfoutput> | Numero Pagina: <cfoutput>#dett_piazz.numpagtl#</cfoutput></strong></td></th>
</thead>
<tbody>
<tr>
<td><strong>Codice</strong></td>
<td><strong>Terminale1</strong></td>
<td><strong>Terminale2</strong></td>
<td><strong>TerminaleC</strong></td>
<td><strong>Assegnazione</strong></td>
<td> </td>
</tr>

<cfoutput query="dett_piazz">
<cfform name="ass_#codicesl#">
<cfinput type="Hidden" name="codicesl" value="#codicesl#">
<tr>
<td>#codicesl#</td>
<td>#terminale1#</td>
<td>#terminale2#</td>
<td>#terminalec# #id_macchina#</td>

<cfquery name="macchine" datasource="intranet">
select id_macchina from tab_macchine <cfif id_macchina neq 0>where id_macchina <> '#id_macchina#'</cfif>
</cfquery>

<td >
<cfif currentrow eq 1>
<select name="id_macchina#recordcount#">
<cfif id_macchina eq 0>
<option value="0" selected>Seleziona</option>
<cfelse>
<option selected>#id_macchina#</option>
</cfif>

<cfloop query="macchine">
<option>#id_macchina#
</cfloop>
</select>
</cfif>

</td>
<cfif stato eq 2><td bgcolor="green"><cfelseif stato eq 1><td bgcolor="yellow"><cfelse><td bgcolor="red"></cfif> </td>

</tr>
<cfif currentrow eq dett_piazz.recordcount>
<tr><td colspan="6">
<!--- <cfif len(id_macchina) gt 2>
<cfdiv bind="url:aggiorna_assegnazione.cfm?codicesl={codicesl}&id_macchina={id_macchina}&n_tagtl=#url.n_tagtl#&ass=1">
<cfelse> --->
<cfdiv bind="url:aggiorna_assegnazione.cfm?codicesl={codicesl}&id_macchina={id_macchina#currentrow#}&n_tagtl=#url.n_tagtl#" id="theDiv_#currentrow#">
<!--- </cfif> --->
</td></tr>
</cfif>
</cfform>

</cfoutput>

</tbody>
</table>
<hr size=1>
</cfloop>

CODICESL should be something like "aaa,bbb,ccc" relative only to each form, instead it relative to ALL forms (distinguished by ASS_#CODICESL#) so it's "aaa,bbb,ccc,ddd,0" etc...

can anybody help me? thanks!

Comment 23 by Jason Fisher posted on 6/17/2010 at 7:32 PM

my guess would be that there is another form field called 'codicesl' within the aggiorna_assegnazione.cfm which is added to your form via the cfdiv bind

Comment 24 by Antonio posted on 6/21/2010 at 10:14 AM

Yes that's correct.
Each record creates it's own form. Then using a bind to a cfdiv it should submit the fields requested. Instead it passes ALL the id_macchina values found in the document. How do i refer to a specific form field in cfdiv/bind? Something like:

<cfdiv bind="url:aggiorna_assegnazione.cfm?codicesl={codicesl}&id_macchina={ass_#codicesl#.id_macchina}&n_tagtl=#url.n_tagtl#&ass=1">

so that the id_macchina value is specific to the form named ass_#codicesl# ?

Thanks again,

Antonio

Comment 25 by Mik Muller posted on 8/4/2010 at 3:15 AM

Hey all,

Is there a known bug with cf/input type="file" inside a cfform in a cfdiv? It always come up empty on post.

Here's the relevant code. Again, it's inside a cfdiv.

<cfform action="/modalUploads.cfm?mode=upload" method="post" id="loginForm" enctype="multipart/form-data">
<cfinput type="File" name="upload_file">
<select name="transparent">
<option value="">No transparent colors</option>
<option value="white">Remove white background</option>
<option value="black">Remove black background</option>
<option value="">Not an image</option>
</select>
<select name="colors">
<option value="0">Preserve image colors</option>
<option value="1">Convert to one-color</option>
</select>
<input type="submit" name="submit" value="Upload!" class="submit-button" />
</cfform>

Mik

Comment 26 by Raymond Camden posted on 8/4/2010 at 4:18 AM

It's expected. I actually have another blog on that somewhere here. Forms inside of cfdiv turn into Ajax posts, and you can't do file uploads over an Ajax post.

Comment 27 by Mik Muller posted on 8/4/2010 at 8:07 AM

Hmmm.... so, what's the solution? Pop ups instead of cfwindows? FTP?

Comment 28 by Raymond Camden posted on 8/4/2010 at 4:12 PM

There are many solutions actually - just google for ajax file upload. CF9 includes a cffileupload tag just for this purpose. I also recommend Uploadify.

Comment 29 by learning posted on 1/11/2011 at 10:34 PM

Hi Raymond:

I'd appreciate your help on this. I'm using the CFLAYOUT tag in a page. Basically, the user, once logged in to the site can scroll down to the "feedback section" which is a simple form within the CFLAYOUT tags, fill it in & submit. It works fine. so assuming the feedback form is on feedbackpage.cfm, once submitted, the variables(name, address, feedback etc) are posted to the processing page(action.cfm) which then posts back & appears in (replaces) the feedback form area on feedbackpage.cfm.

The question however is this. How do I get the form(based on user input) to reappear on the feedbackpage.cfm in case a user wants to send another feedback? If I use the refresh button, it works fine but I require a more professional touch. It wouldn't be nice to ask the user to "click on the browser refresh button" in order to send another feedback. I would really appreciate your help on this.

Thanks Raymond.

Comment 30 by learning posted on 1/11/2011 at 10:36 PM

...by the way, I'm using the VBOX type CFLAYOUT.
<cflayout type="vbox" name="layout_a">.

Thanks.

Comment 31 by Raymond Camden posted on 1/13/2011 at 9:21 AM

There is a JS function you can use called ColdFusion.navigate. It lets you load a URL into a layout section. See the CFML reference for details.

Comment 32 by Learner posted on 1/14/2011 at 5:56 PM

Thanks Raymond, I'll try again but had tried using it earlier. Would you be kind enough to break it down [further] please? Still learning.

Thanks.

Comment 33 by Learner posted on 1/14/2011 at 6:01 PM

...I used a CFFORM tag within the CFLAYOUT, so the first 3 lines basically are these:

<cflayout type="vbox" name="layout_a">
<cflayoutarea>
<cfform action="action.cfm" method="post" name="enquiry_form">

Pls how do I make appropriate use of the ColdFusion.navigate function u mentioned?

Thanks.

Comment 34 by learning posted on 1/14/2011 at 9:33 PM

Thanks Raymond, It's working now with a bit of some bugs. Just requires some minor tweeking. Currently, I created a 2nd form (in a 3rd .cfm page)so when the link on the action.cfm page is clicked, the form on the 3rd page loads into the LAYOUT.
Thanks.

Comment 35 by Raymond Camden posted on 1/14/2011 at 9:35 PM

Cool - glad you got it.

Comment 36 by learning posted on 1/14/2011 at 9:38 PM

Thanks, working alright now. IF You however have a way of keeping the whole thing to just 2 instead of the current 3 pages, kindly let me know please. & thanks gain for your help.

Comment 37 (In reply to #35) by coldnewbie posted on 1/5/2015 at 2:44 AM

I am using

<cflayout type="border" name="mainTab">

<cflayoutarea position="left" splitter="true" title="DB_Jobspec" name="DB_Jobspec" style="width:520px;">
<cfoutput query="qgetdcfg">

.....

<cflayoutarea position="center" name="exam" style="border:30px solid red">
<cfif structkeyexists(url,="" "datasource")="">
..... etc.,

with a left and center. The left -- tab is fine and works. It basically pulls data from a database, whenever user clicks on one of the rows, it has bring up a detailed page on the center layoutarea - with some relevant details.

There are no errors- but nothing happens - i.e., the center tab does not show up.

I am a newbie to coldfusion. thanks

Comment 38 (In reply to #37) by Raymond Camden posted on 1/5/2015 at 3:20 AM

Doesn't help, but the best recommendation I can give is to avoid cflayout like the plague.