Quick tip - using ColdFusion.navigate instead of bindings

A user pinged me during MAX (what's wrong with you guys, didn't I warn you about questions??!? ;) with a problem. He wanted to use a CFDIV tag that bound to a form. The problem was - he didn't want to actually do anything until the form was complete. He was using bindings, and everytime the form changed, the div reloaded, even though the form wasn't complete. There are two simple solutions to this.

First off - one simple solution is to build the source file, and by source file I mean what your CFDIV is pointing to - build it such that it recognizes an incomplete form and simply doesn't do anything. So consider this form:

<form id="myform"> Name <input type="text" id="name" name="name"><br> Age <input type="text" id="age" name="age"><br> </form>

You could simply check to see if name and age have values before you output a response. But that doesn't technically answer his question. He wants the CFIDV to do nothing at all until the form is done.

So the second option is to just use a submit handler or a button to run a JavaScript function. This function can check the form - and when happy, use ColdFusion.navigate, or ColdFusion.Ajax.submitForm. I tend to prefer navigate, so here is an example.

<script> function checkForm() { var name = document.getElementById("name").value; var age = document.getElementById("age").value; //Employ Mr. T error handling if(name == '') { alert('Enter a name, fool!'); return false; } if(age == '') { alert('I pity the fool who doesn\'t have an age!'); return false; } ColdFusion.navigate('div.cfm?name='+escape(name)+'&age='+escape(age),'resultdiv'); return false; } </script>

<form id="myform"> Name <input type="text" id="name" name="name"><br> Age <input type="text" id="age" name="age"><br> <input type="button" value="Test" onClick="checkForm()"> </form>

<cfdiv id="resultdiv" style="background-color:##fff271" />

As a quick FYI, div.cfm simply dumped the URL scope, and the background color on the div was just me being fancy.

Archived Comments

Comment 1 by Scott Stroz posted on 10/5/2007 at 3:42 AM

I have come to really like ColdFusion.navigate() and ColdFusion.AJAX.submitForm()

Comment 2 by James Edmunds posted on 10/5/2007 at 6:18 PM

ColdFusion.navigate() is very, very cool.

Comment 3 by Victor posted on 10/6/2007 at 11:11 PM

When I run the code it complains about:
Attribute validation error for tag CFDIV.
The tag requires the attribute(s): BIND.
even though the BIND attribute is not mandatory

Comment 4 by Raymond Camden posted on 10/7/2007 at 11:40 PM

Victor, are you running the FINAL version of CF8?

Comment 5 by Victor posted on 10/8/2007 at 5:39 PM

As far as I know yes. I have version: 8,0,0,171647

Comment 6 by Raymond Camden posted on 10/8/2007 at 5:41 PM

I don't think so. My v is:

8,0,0,176276

Comment 7 by Victor posted on 10/8/2007 at 6:05 PM

Did you apply the last hot fix?
I did but I had an error and had to reverse back to the original installation. I will try to re-install it and see if it fixes the issue.

Comment 8 by Raymond Camden posted on 10/8/2007 at 6:11 PM

Not yet, but my V is higher than yours. :)

Comment 9 by Victor posted on 10/9/2007 at 5:39 PM

Indeed it was.

I had to re-install CF8 and now my V is like yours :)

Thanks

Comment 10 by Don posted on 9/1/2009 at 11:00 PM

So once a cfform is submitted, how do I get the original cfform to show and not just the return back from the form handler? And how do I navigate to any specific tab in a cflayout? AND is this the right place to ask this? (Sorry, been all over the net and can't find answers to these questions)

Comment 11 by Raymond Camden posted on 9/2/2009 at 4:32 AM

The second question is the easiest. You don't navigate _to_ a tab. You can select a tab. Check the CF AJAX reference docs for that API. If you want a tab with a form to post to itself, it should be pretty easy. If I remember right, a CFFORM based form inside a tab will perform an ajax based post to itself. Have you tried it yourself?

Comment 12 by Ranga posted on 6/17/2010 at 5:34 AM

Thanks for sharing the code. I was using <CFDIV BIND="source.cfm?hid={hiddenid}" />. The problem was the DIV never refreshed when the hidden field was updated. CFDIV refreshes with no issues when the same field was changed to a text field. So, instead of cfdiv bind, I used the approach in this page and was able to refresh contents of the CFDIV tag.

Thank you!

Comment 13 by Mik Muller posted on 9/4/2010 at 1:21 AM

Here's a funky one... how would you use ColdFusion.navigate() to refresh a CFDIV if you don't know what was currently *in* the CFDIV?

For example. You may have a CFDIV you use as a generic container to display messages from various feeds by stuffing a variety of CFM files into a singular ID:

ColdFusion.navigate('/feedOne.cfm','divGeneric');
ColdFusion.navigate('/feedTwo.cfm','divGeneric');
ColdFusion.navigate('/feedTwo.cfm?mode=hoohah','divGeneric');

If you needed to refresh 'divGeneric' with whatever was last used... would you use something like this...?

ColdFusion.navigate(document.getElementById("divGeneric").value,'divGeneric');

My guess is no, since the DOM doesn't know what CFM file was used to create the current content.

Hmm... keep a variable in the SESSION scope?

It would be extremely handy if the CFDIV remembered what last went into it so we had a ColdFusion.navigate.(last,'divGeneric');

Comment 14 by Raymond Camden posted on 9/4/2010 at 1:25 AM

I'd just store it a JS variable. Every time you want to change dix X to url Y, use a simple function that remembers Y and does the ColdFusion.navigate for you.

Comment 15 by CJ posted on 3/31/2011 at 6:24 PM

I am trying to make a registration form and check Username availability on the fly. I have it working with ColdFusion.navigate, but I want the colorize the result. If it is available, I want the text to display green, if already used then display red. Any ideas on how to do this?

Here is my code:

From the form:
<cfinput type="Text" name="Username" style="width:125px;" maxlength="25" required="Yes" message="You Must Enter a User Name" onFocus="this.value='';"><cfdiv id="AvailabilityDiv" /><cfajaxproxy bind="javascript:loadDiv({Username})"></div>

cfc call:
<script>
function loadDiv(value) {
// Change the contents of the CFDIV
ColdFusion.navigate('live-checkuseravailability.cfc?method=getData&UserAvail='+ value, 'AvailabilityDiv');
}
</script>

And my CFC:
<cfcomponent>
<cffunction name="getData" returnType="string" access="remote">
<cfargument name="UserAvail" type="string" />

<cfquery name="chkUsername" datasource="#application.DSNName#">
SELECT *
FROM UserAvail
WHERE Username = '#UserAvail#'
</cfquery>

<cfif chkUsername.RecordCount GTE 1>
<cfreturn "Username Already exists">
<cfelse>
<cfreturn "Username available to register">
</cfif>
</cffunction>
</cfcomponent>

Any help would be greatly appreciated.

Comment 16 by Raymond Camden posted on 4/1/2011 at 12:29 AM

Not the most elegant, but in your return just wrap the string in a class.

<cfreturn "<span class='green'>Username available</span>">

This assumes you have a class for green (and red, etc) in your template.

Comment 17 by CJ posted on 4/1/2011 at 1:34 AM

Thanks Ray,

But when I do that line of code like this:
<cfreturn "<span class='green'>Username available to register"</span>>

I get this error:

Error retrieving markup for element AvailabilityDiv : Invalid CFML construct found on line 14 at column 95. [Enable debugging by adding 'cfdebug' to your URL parameters to see more information]

Comment 18 by Raymond Camden posted on 4/1/2011 at 1:37 AM

You out the closing span outside of the string. Move your last quote to after the end of the span.

Comment 19 by CJ posted on 4/1/2011 at 1:44 AM

thanks, guess another set of eyes are good. But now I have another issue. It displays the whole string
<span class='green'>Username available to register</span> in the div area, not the "Username available to register" in green

Comment 20 by Raymond Camden posted on 4/1/2011 at 1:49 AM

Well that's odd - you should be able to return HTML to the div. Let me test.

Comment 21 by Raymond Camden posted on 4/1/2011 at 1:51 AM

Oh, I think I know your issue. Before I get into it, try this test for me and then I'll explain. change

ColdFusion.navigate('live-checkuseravailability.cfc?method=getData&UserAvail='+ value, 'AvailabilityDiv');

to

ColdFusion.navigate('live-checkuseravailability.cfc?method=getData&returnformat=plain&UserAvail='+ value, 'AvailabilityDiv');

Comment 22 by CJ posted on 4/1/2011 at 1:55 AM

Awesome... That works. So what does this mean?

Comment 23 by Raymond Camden posted on 4/1/2011 at 2:01 AM

Your code said, in English:

"ColdFusion, I want you to navigate, ie, load, the result of calling this CFC method."

By default, when you run a CFC method remotely, it returns WDDX, an XML version of the result. If you were to open that URL in your browser and view source, you woulda seen an XML version of the string.

When I had you add "returnformat=plain", it was telling ColdFusion to not do ANYTHING with the result, but rather just return it as is.

This only works with simple results. You couldn't return an array like that.

You can stop reading now - what follows is sermon. ;)

Typically though you don't return layout in a CFC. I'd have called the CFC method and have it return 0 or 1, with 0 being the bad result, and 1 the good, and your front end code would handle displaying the appropriate message. Your CFC - typically - should be a black box of business logic: "If this username OK? YES OR NO - Period." Stuff like "what class do I use to render a good output" would be a concern of the front end.

End of Sermon.

Comment 24 by CJ posted on 4/1/2011 at 2:23 AM

Thank you very much and thank you for the explanation and your time.

I see what you are saying and I actually tried a few things and that seems to be what I got working. What I was struggling with was where I get the result, I guess what variable holds the result. I tried a few things and kept getting errors, so that Is when I did it the "wong" way, but it worked. I see what you are saying and that would be a lot better. I just did not know how to do it.

I have done CF for many years, but some areas I still have a ton to learn. Again, Thanks for your time.

Comment 25 by Raymond Camden posted on 4/1/2011 at 2:30 AM

You should not feel like you did it the "wrong" way- and sorry if I came off too strongly. I'd just say "Not recommend normally" instead of "wrong". Your code is working now - that's the critical thing. :)

Comment 26 by CJ posted on 4/1/2011 at 2:50 AM

No problem, I did not take offense and I agree. If I can ask you one more question, now that I have been thinking about it since I wrote my last comment, how would I find the value of Yes or No passed back from the CFC the way you said to do it? Sorry for taking up so much of your time.

Comment 27 by Raymond Camden posted on 4/1/2011 at 5:39 PM

Well, ColdFusion.navigate is basically doing a "Load this crap into a div". In order to call a CFC and "work" with the result, you would need to do something a bit different.

1) If you want to stick with CF's Ajax stuff, you can look at cfajaxproxy. It allows you to turn a CFC into a JavaScript object. You would then be able to make calls on methods and work with the results directly.

2) Myself - I don't make use of CF's front end Ajax stuff. I use jQuery instead. I'd use jQuery's ability to run a HTTP request and work with the response.

Obviously I'm talking high level here.

Comment 28 by CJ posted on 4/2/2011 at 5:21 PM

Thanks for the response.

I will have to do some studying on what you said. I appreciate the feedback and direction. Got some learning to do.