Ajax Form Submission Revisited And Advice Needed
Posted By : todd sharp Posted At : August 13, 2007 12:21 PM Posted In: ColdFusion
14
Ray blogged last week about Async form submission with ColdFusion 8 Ajax containers. This is a really cool feature but a reader commented about wanting the ability to submit a form using JavaScript like so:
The problem with trying to do this is that you're circumventing the process a bit. Much of the magic behind this Async submission is quite complicated. That's the beauty of ColdFusion - it takes a mess of a process and makes it seemless to us. It just works. So this magic happens when a form is submit - but it all starts in the onSubmit handler of the form itself which looks something like this:
When trying to use JavaScript to submit the form, unfortunately you will not have the benefit of the onSubmit handler being fired. Therefore the submission will not be async and you'll lose out on the cfform validation (but who really uses that anyways).
So what happens when a form is submitted inside a dynamic container? I took a peak at some of the magic with Firebug and what follows is my understanding of the process - I may not be 100% correct but I feel like it's pretty close.
So first off the internal (read: undocumented) ColdFusion.Ajax.checkForm is called. The form itself is passed (this) followed by the cfform JS validation function name (_CF_checktestForm) and finally the Ajax container in which the form is held (in my case a tab named 'login'). Long story short, the form is validated and submit (via ColdFusion.Ajax.submitForm I'm sure) and the original container's innerHTML replaced with the response body of the async form submission. Could this be replicated manually? Sure. Would it be nasty looking? In my opinion, yes. Since your Ajax container and your form are two different templates you'd have to use a method for Ajax submission (an ajaxproxy or submitForm) and then replace the main template container contents with the response body.
So hopefully that explanation makes sense. That being said does anyone have any other ideas for async form submission using JavaScript with CF 8 Ajax containers?



layout.cfm
<cflayout type="tab">
<cflayoutarea name="login" source="login.cfm" />
</cflayout>
login.cfm
<cfif form.submit...>
thanks for submitting.....
</cfif>
<cfform name="testForm">
<cfinput ...>
<cfinput onclick="ColdFusion.Ajax.submitForm('testForm', 'login.cfm', myCB, myErrorHandler); />
</cfform>
So login.cfm is the source of the tab in layout.cfm. If I use ajax.submitForm it simply takes the form and posts it (in this case to itself) but doesn't actually do anything with the response body (which would be the 'thanks for submitting...'). In myCB I *could * take that response body and stuff it in the innerHTML of login (the id of the tab in layout.cfm) but that feels really hacky to me. Plus what happens when someone renames the ID of the tab 'login' to 'superLogin'? Now I've hardcoded the ID and things are broken.
Does that make sense? In other words I could manually replicate what the default behaviour is but it isn't fool proof.
Also, if you do anything with the AJAX JavaScript functions you're going to have to reference the element through it's ID, so if the goal is to try to avoid any direct references to any DOM elements by their ID, you're going to be either very limited in what you can do, or you're going to have to set up a set of global aliases for the IDs that you can use in both your JavaScript calls and in the actual HTML where you create and identify the element in question.
Basically, I see no problem handling the callback yourself (almost anything complex that uses the new AJAX functions will require a custom function anyway), nor any problem in referencing the ID (again, you're going to have to do this in just about any custom JavaScript function you write that handles AJAX processing).
Personally I think I'll be using an ajaxproxy in most situations. I feel perfectly comfortable with callbacks and pushing the generated markup into a container.
I am with you here even though it sounds like I'm talking my way around it ;)
If you think of the DOM IDs as the "API to your display elements", there's no real problem with referencing them from outside of the template. And once the template is finished it is unlikely that the IDs are going to change a lot. And again, if they do, the key is to have one place to maintain the JavaScript.
It's the same idea as a CFC: your CFC has methods and arguments, and if you change those, external code is going to have to change too. There's really no way around it, but there are ways to minimize the impact of the changes.
ColdFusion.navigate(); in this way:
ColdFusion.navigate('urlToFile.cfm','updateElement','callback','errorhandler','POST','formID');
<cfform name="test">
<cfinput type="Submit" name="submit" class="formbutton" value="UPDATE" />
GOOD FOR SELECT MENUS
onchange="document.test.submit.click();"
GOOD FOR OTHER STUFF
onclick="document.test.submit.click();"
Basically, this simulates clicking on the update button.
Sorry to bother you, but Im fighting this thing for a couple of days now. http://www.multilistmanager.com/views/formtest.cfm...
Any idea why Im receiving this: "Error while updating Error code: 500 Message: OK"
The form is submited to a cfc function with just a simple cfmail using the the form values to send an email.
Thanks in advance
Felipe Serrano
Thanks Todd
But how can you pass or set form.scope variables to be in arguments.scope from cfform?
Thanks Todd
<cfdump var="#arguments#" format="html" output="#expandPath("dump.html")#" />
Then submit the form and go take a look at what is dumped in the dump.html.
I'd be willing to bet you'll see all your form values in the arguments struct. If thats not the case you may want to submit to a CFM page that then calls your CFC, passing the form variables. That probably is a better idea anyways since you can then do some validation before calling the CFC.
document.formname.onsubmit();
just call the onsubmit method yourself.