Raymond Camden's Blog Rss

Simple example of a Form post to ColdFusion with jQuery

26

Posted in jQuery, JavaScript, ColdFusion | Posted on 03-20-2009 | 18,812 views

Following up on my earlier post demonstrating loading ColdFusion query data via jQuery, I've decided to do a few more simple jQuery+ColdFusion examples to give folks a taste of how easy it is to work with them both at the same time. For today's entry I'm going to show a very simple form post. This is as about as trivial as you can get, but I'm going to follow it up the next few days with a few more examples that will build upon it. So with that in mind, let's take a quick look at the code.

First I'll show the form. Notice that for this example I will not be doing any form validation. I want to keep things as nice and simple as possible.

view plain print about
1<form id="testForm">
2    Name: <input type="text" name="name"><br/>
3    Email: <input type="text" name="email"><br/>
4    Gender:
5    <select name="gender">
6    <option value="M">Male</option>    
7    <option value="F">Female</option>
8    </select><br/>     
9    <input type="submit" value="Save" />
10</form>

The form contains 3 fields: name, email, and gender. Notice I did not supply an action for the form. I'm going to let jQuery do everything. Now for the JavaScript.

view plain print about
1<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
2<script>
3$(document).ready(function() {
4    $("#testForm").submit(sendForm)
5});
6
7function sendForm() {
8    $.post('post.cfm',$("#testForm").serialize(),function(data,status){
9        $("#result").html(data)
10    });
11    return false
12}
13
14</script>

The first block of code simply says: When the page loads, I want you to bind the submit action of the form caleld testForm to a function called sendForm. This basically takes over the submit action. sendForm is a grand total of two lines. jQuery provides multiple ways to do Ajax calls. I'm using post for this example. The post function lets me specify a URL, some data, and a callback function. If callback functions confuse you (they were for me at first), just think of it as me telling jQuery: "Hey pal, when you are done sending the data, please run this function with the result."

How do I get the data? In the old days I might have used document.getElementById() on all the form fields. Luckily jQuery provides not one but two functions to handle this task for me. I can use serializeAray() to turn a form into a javaScript object. It will go throughout all the fields and create a name/value pair. It will be smart enough to know what to do for textfields, checkboxes, drop downs, you name it. An alternative to this is the serialize() function. This creates a string (think query string) version of the form data. The post() function will use either of these.

My callback function simply takes the result, trims it (don't forget how much ColdFusion likes whitespace!), and displays it within a div.

The ColdFusion side isn't doing much here. Let's take a look:

view plain print about
1<cfparam name="form.name" default="">
2<cfparam name="form.email" default="">
3<cfparam name="form.gender" default="">
4
5<cfoutput>
6Thanks for writing,
7<cfif form.gender is "m">Mr<cfelse>Ms</cfif> #form.name#.
8I've sent a subscription email to #form.email#.
9</cfoutput>

I do some basic validation on top and then simply output the result. I mention sending a subscription email, but don't really do it. (How many people think quite a few web apps lie like this?)

You can demo this here: http://www.coldfusionjedi.com/demos/jqform/test2.html

Ok, so pretty simple, but there are some things to think about it.

First, if I just wanted to load the result of posting the form into the div, I could have used the jQuery load function instead. I wanted to show a bit more... control over the process, so I used post() instead. I've said this before, but please remember - like ColdFusion, jQuery almost always provides more than one way to do somrthing.

Second, my form does zero error handling. Since I'm just dumping the result in a div, I could have done error handling in ColdFusion. What about errors in general? You can see I have access to a status variable. But as the docs say, this always returns true. This seems like a bug in jQuery, and it seems like it should be something simple to fix, so I'm assuming the issue is a bit more complex. In my testing, when I forced an error in the ColdFusion side, I still got 'success' for a status.

Third, just showing a message as the result is the simplest way to handle the result of the post. I could have also hidden the form. I could have done anything number of things really. What's nice though is how jQuery makes it easy to package up and wrap the logic all within a few lines. jQuery FTW!

Lastly, I mentioned I was going to skip client side validation in this post. I skipped it not because it was difficult, but because I wanted to create a simple example. I wrote a few blog entries on the topic and you should definitely check it out. (An introduction to jQuery and Form Validation)

As always, comments from the jQuery experts are welcome (well, any comments are welcome). My general plan for followups to this entry include: jQuery and a Login Form demo. jQuery and a Search Form demo. jQuery and a CAPTCHA demo where you can reload the CAPTCHA.

Comments

[Add Comment] [Subscribe to Comments]

Ray, have you looked into the awesomesause that is jQuery form plug-in? ( http://www.malsup.com/jquery/form/ )

~Todd
@Ray
You kind of touched on it a bit in your post but I'm still confused as to what seasoned jQuery developers are using in comparison to CF's setErrorHandler and setCallbackHandler functions. I totally see where you're building the callback into the one line submitter but how would this work if we were doing something more advanced than a form submit. For instance, calling a function that lives in a cfc to check for the existence of a conflicting primary key before we decided to even do the form submit.
Thanks for posting this, I may soon step outside of my comfort zone with CF's Ajax set and learn jQuery. I haven't been convinced yet and the jQuery team may have to call me and sing "If you don't know me by now" before I'll climb aboard.
@Todd: Nope. I can put it on my list though. In general I'm trying to avoid plugins for these blog entries. I kinda feel like the plugins can be a bit overwhelming to new jQuery users. Having multiple ways to do X is good. Having 500 ways to do X is overwhelming at times. :)

@Andy: So as I said, you can't really handle the error with .post. You _always_ get success back. You could return data that means something. By that I mean, instead of just a string like I did, I could have returned 0, which would mean 'bad', or 1, which would mean 'good'. Using the ajax() method gives you more fine grained control.

I'm still learning this stuff myself, so please keep that in mind. I'm not the expert here. ;)
@Ray: I agree with you, but there's a handful of plugins I can't live without:

* form ( http://www.malsup.com/jquery/form/ )
* metadata ( http://plugins.jquery.com/project/metadata )
* validate (you discussed previously - http://docs.jquery.com/Plugins/Validation)
* uiblock ( http://www.malsup.com/jquery/block/ )

That's about it. None of my project begin without me copying these base plug-ins and putting them in place.
Regarding error handling... for client side errors you can catch those before the $.post is even called. For server side errors, like Ray said, you can return anything. Like Ray mentioned, you could return "Successful update" and then show the values. Or you could return "Update failed" and an error message.

You could also return a json object that has a success flag (0/1 or T/F), a message string, and the form values.
I have a question that is somewhat related to this post. I've been using a combination of JQuery and Coldfusion 8 for a while now and find them both indespensible. For ease of use, I've got a form that I am submitting via AJAX through CF8.
I am using CFAJAXPROXY to bind to a CFC like this:

<cfajaxproxy cfc="aqs3.contacts" jsclassname="CM">

Now, what I would like to do is access different methods of this CFC with information from several forms on the page. I know I can use the XXX.SetForm("formname") syntax to bind ALL of the values on the form to the method using named attributes. But what if I only wanted to call a method with a few of the form values? I can use JQuery (or simple JS) to get the values I need, but I can;t find a way to pass them as named attributes.

Since the SetForm command seems to figure out a way to do this, it must be possible, but for the life of me I can;t figure out how.

Any ideas?

--Sean
That's a lot of code to do that. But it is what it is. I've been using jquery a lot myself lately.

For my web forms I've been using these guys:

http://www.formmailhosting.com

They do the form to email processing for me, but I like the example you came up with.

ERIC
Eric - you really think that's a lot of code? Looks pretty slim to me.
Ray, love the blog, nice example here again. I'm trying to upload a file using this technique. I have the below inputs in my form, and when I read the data like you showed using CF, I'm able to get the title field slick as can be, however, the uploadfile field is undefined when trying to retrieve it.

<input type="text" name="title">
<input type="file" name="uploadfile">

Any advice? Thanks
@Sean: If you want to use some form fields but not all, you would need to do it manually, or bind using specific form fields: {field1},{field2},{etc}. You really have to either take it all or do it manually one by one (which makes sense if you think about it).

@Travis: You can't do file uploads via Ajax. Period. You can only do it with iframe type hacks (which, for all intents and purposes ends up looking like normal Ajax). Please search my blog as I did an entry on this a few months ago.
Hi Ray -

I would like to add error checking to a form that I've created using this method. I have placed the error checking on the page that holds the form code (index.cfm) and have the form results post to another page (consultationPost.cfm). However, no matter where I place the form validation code, it isn't processed and the form results simply post without being validated.

Do I need to use jquery validation in this instance or am I just doing something wrong.

Thanks for any help,
Adam
This is a great post, I've been dipping my toe into this area much more recently, but I was missing the odd point here and there, and you've filled the gaps in for me. Hopefully one day the JQuery will 'roll off the tongue' like the CF does. until then I'll probably be stealing all your blogs on it :-)
@Adam: This sounds like an error is occurring. Have you looked at Firefox's Error window?
Hi Ray -

I've removed all error checking and have two forms. One is similar to your test2.html:

   <cfoutput>
      
      <cfform id="consultationForm">
         <div id="consultations">
                   <!--- Our form submission flag. --->
          <input type="hidden" name="submitted" value="1" />

            <fieldset>
               <legend>Consultations</legend>            
                  <label for="client name">Client Username
                     <cfinput id="clientID"
                           name="clientID"
                           type="text"
                           value=""
                           maxlength="8"
                           <!---
                           onClick="ColdFusion.Window.show('userWin')"
                           bind="{clientLookup.client}"--->
                           />
                     
                  </label>
                  <label for="consultation date">Consultation Date
                     <input name="consultationDate" type="text" id="datepicker" />
                  </label>
                  <label for="consultation type">Consultation Type<br />
                     <select name="consultationType">
                        <option value="">&ndash; select &ndash;</option>
                        <option value="phone">Phone</option>
                        <option value="email">Email</option>
                        <option value="faceToFace">Face To Face</option>
                        <option value="online">Online</option>
                     </select>
                  </label>
                  
                  <div class="clearer"></div>                  

                  <label for="Instructional Technology">Instructional Technology
                     <select id="instructionalTechnology" name="instructionalTechnology">
                        <option value="">&ndash; select &ndash;</option>
                        <option value="Oncourse">Oncourse</option>
                        <option value="Eportfolio">Eportfolio</option>
                        <option value="Web conferencing">Web conferencing</option>
                        <option value="Podcasting">Podcasting</option>
                        <option value="Video">Video</option>
                        <option value="Audio">Audio</option>
                        <option value="Turnitin">Turnitin</option>
                        <option value="Learning Objects">Learning Objects</option>
                        <option value="Web Development">Web Development</option>
                        <option value="Student Response Systems">Student Response Systems</option>
                        <option value="Collaborative web technology">Collaborative web technology</option>
                        <option value="Technology (other)">Technology (other)</option>
                     </select>
                  </label>
                  <label for="Instructional Design">Instructional Design
                     <select id="instructionalDesign" name="instructionalDesign">
                        <option value="">&ndash; select &ndash;</option>
                        <option value="Classroom Observations">Classroom Observations</option>
                        <option value="SGID">SGID</option>
                        <option value="Course Design">Course Design</option>
                        <option value="Syllabi">Syllabi</option>
                        <option value="Teaching Portfolio Development">Teaching Portfolio Development</option>
                        <option value="Assessment of Student Learning">Assessment of Student Learning</option>
                        <option value="SoTL ">SoTL</option>
                        <option value="Classroom Management Issues">Classroom Management Issues</option>
                        <option value="Academic Integrity">Academic Integrity</option>
                        <option value="Inclusive Teaching">Inclusive Teaching</option>
                     </select>
                  </label>
                  <div class="clearer"></div>                  
                  
                  <label for="tags">Tags
                     <input id="tag1" name="tag1" type="text" maxlength="50" value="" tabindex="8"/>
                     <br />
                     <input id="tag2" name="tag2" type="text" maxlength="50" value="" tabindex="8"/>
                     <br />
                     <input id="tag3" name="tag3" type="text" maxlength="50" value="" tabindex="8"/>
                     <br />
                     <input id="tag4" name="tag4" type="text" maxlength="50" value="" tabindex="8"/>
                  </label>
                  <label for="internal notes">Internal Notes<br />
                     <textarea name="internalNotes" cols="20" rows="10" tabindex="7"></textarea>
                  </label>   
                  <label for="notes to client">Notes to Client<br />
                        <textarea name="clientNotes" cols="20" rows="10" tabindex="9"></textarea>
                  </label>
                  <input type="hidden" value="#Now()#" />
             <input class="submit"type="submit" value="Submit" /> <input class="reset" type="reset" value="Reset">
             <div id="clearer"></div>
            <div id="result"></div>               
            </fieldset>
         </div>
      </cfform>


My post.cfm is consultationPost.cfm and currently includes:

<cfoutput>

      <cfquery name="qAddConsultation" datasource="myDSN">
      
         INSERT INTO TEMPconsultations (submitDate,
                           transID,
                           weekOfYear,
                           username,
                           clientID,
                           consultationDate,
                           consultationType)



         VALUES ('#DateFormat(now(), "mm/dd/yyyy")#',
                  '#transID#',
                  '#theWeek#',
                  '#trim(session.username)#',
                  '#trim(clientID)#',
                  '#trim(consultationDate)#',
                  '#trim(consultationType)#')
         
      </cfquery>


   
   
   
   <strong>Client</strong>: #form.clientID#<br />
   <strong>Consultation Date</strong>: #form.consultationDate#<br />
   <strong>Consultation Type</strong>: #form.consultationType#<br />

   <strong>Instructional Technology</strong>: #form.instructionalTechnology#<br />
   <strong>Instructional Design</strong>: #form.instructionalDesign#<br />
   <strong>Tags</strong>: #form.tag1#, #form.tag2#, #form.tag3#, #form.tag4#<br />
   <strong>Internal Notes</strong>: #form.internalNotes#<br />
   <strong>Notes to Client</strong>: #form.clientNotes#
</cfoutput>


All works well until I include the query to write to the database.

I did not see an error window in Firefox and I'm not too familiar with the feature. This conversation tells me I need to.

Thank you.
You should stop using cfform if you wish to use jQuery validation. cfform has it's own validation libraries and routines and they can interfere with custom code.
awesome! thanks!!
Once again, you helped me find out what I was doing wrong. Appreciated!
Hi, I am testing this code in IE7, but it seems like not working...Can you test to see if it works in your IE? Thanks.
I don't have IE7 myself. How does it appear to not be working? If you use a network monitoring tool like Charles do you see the post?
Thanks Ray, it works right now...i guess it's old CF version cause problem...
My forms post back to themselves and handle updates and deletes based on the button clicked. I was also finding that the serialize method was not sending my submit input values. So I added a few lines to the sample above and now it sends a formaction value based on the submit button.

<script src="/jquery/jquery-1.4.4.min.js"></script>
<form id="testForm">
   <input type="hidden" name="formaction" id="formaction" value="noaction">
   Name: <input type="text" name="name"><br/>
   Email: <input type="text" name="email"><br/>
   Gender:
   <select name="gender">
   <option value="M">Male</option>   
   <option value="F">Female</option>
   </select><br/>    
   <input type="submit" value="Save" onClick="document.getElementById('formaction').value = 'saverecord';" />
<input type="submit" value="Delete" onClick="document.getElementById('formaction').value = 'deleterecord';" />
</form>

<script>
$(document).ready(function() {
   $("#testForm").submit(sendForm)
});

function sendForm() {
   $.post('testform.cfm',$("#testForm").serialize(),function(data,status){
      $("#result").html(data)
   });
   return false
}

</script>
I'd use event handlers for your buttons instead of onClick.
This feature is excellent...thank you. It doesn't seem to display the results with I.E. but fully functional in FF. Any idea why? Am I missing something? The post.cfm page is processing the data as I can send an e-mail; only the result text is missing from I.E.
Works for me in IE9. Are you an older one?
I’m using IE8 and cross scripting with the latest FF.

Thanks,
Um well. Not sure. Sometimes IE is picky when you don't specify a content type, but in our case, we aren't sending JSON or XML back. So - not sure what to tell you. Upgrade to IE9. ;)

[Add Comment] [Subscribe to Comments]