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
I have come to really like ColdFusion.navigate() and ColdFusion.AJAX.submitForm()
ColdFusion.navigate() is very, very cool.
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
Victor, are you running the FINAL version of CF8?
As far as I know yes. I have version: 8,0,0,171647
I don't think so. My v is:
8,0,0,176276
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.
Not yet, but my V is higher than yours. :)
Indeed it was.
I had to re-install CF8 and now my V is like yours :)
Thanks
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)
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?
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!
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');
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.
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.
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.
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]
You out the closing span outside of the string. Move your last quote to after the end of the span.
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
Well that's odd - you should be able to return HTML to the div. Let me test.
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');
Awesome... That works. So what does this mean?
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.
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.
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. :)
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.
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.
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.