jQuery ajax with coldfusion

Ray Camden blogged about this recently and I thought I'd take time out to do some of this jQuery/Ajaxy stuff myself.

I was in the midst of trying to figure out how to to a simple login authentication process with CF8 and jQuery.
I've done this in the past with Prototype and this wonderful ajax library JSMX. Simple library to use..just love it! But, with the times, I figured I should try this "jQuery" thing. Seems to be alot of momentum behind it and there's been a lot of raves. So I dove in.



So let's begin...

First build your form:


<form name="frmLogin" id="frmLogin" method="post">
<fieldset>
<legend>Login here</legend>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><label for="email">Email:</label></td>
<td> <input type="text" size="25" name="email" id="email" /></td>
</tr>
<tr>
<td><label for="password">Password:</label></td>
<td> <input type="password" name="password" id="password" size="25" /></td>
</tr>
<tr>
<td colspan="2"><div id="loginResponse" style="height: 20px;text-align: center;margin-top:10px;"></div></td>
<tr>
<td><br /><input type="submit" name="Submit" id="submitButton" value="Log In"> </td>
</tr>
</table>
</fieldset>
</form>

Nothing new here, just a simple form.

Now, begin adding your customized jQuery script:

$(document).ready(function() {
// attach a submit handler to the form
$("form#frmLogin").submit(function(){

}); // .submit()

});
Pretty self explanatory. Add a submit handler to the submit button. I tried:

$("#frmLogin").submit()
and this didn't work. I had to add in the form scope. Don't know why. But, heck it works now.

Next up, add your ajax handler:

$.ajax({
type: "",
url: "",
data: ,
success: function(){}
});
This is the skeleton for which you'll be adding to.
TYPE= "GET,POST"
URL = url of the calling script to process the data you'll be passing in
DATA= the data you'll be passing in the form of key value pairs
SUCCESS: the function to call when a successful request is made
ERROR: the function to call when a failed request is made (not used in this example)
Next up, figure out what data you'll be passing from your form. Since we only need to pass in the username and password to process through your validation script this works just fine:

var email = $('#email').val();
var password = $('#password').val();
var datastring = "email=" + email + "&password="+password;
Place that above your ajax code. What have you done? You've grabbed the values from the form then concatentated them to a string that's URL worthy :) Speaking of URLs...You do know the cfm/cfc/php script you'll be calling to process the information right? Here's what your ajax call should look like:

$.ajax({
type: "POST",
url: "ajaxtest.cfc?method=loginCheck&returnformat=plain",
data: datastring,
success: function(){}
});
But, then I thought, "what if I have 50 or more field entries? Do I really want to do this 50x over?". Searching the jQuery docs, I stumbled across $(form).serialize!!

var datastring= $('form#frmLogin').serialize();
.serialize method will take your whole form and serialze them into name/value pairs. Now isn't that special? (church lady anyone?)

Since I'm calling a CFC to process my credentials, I have to remember to add the ever important RETURNFORMAT=PLAIN parameter to the URL. If I don't, I will get the information passed back to me in CF's native WDDX format. WDDX won't work for me in this instance. I just want to know if the credentials pass...TRUE or FALSE.

So jQuery will now call this behind the scenes: ajaxtest.cfc?method=loginCheck&returnformat=plain&email=&password=.

The response back from the server will either be TRUE or FALSE. I need to do something with either one of these 2 results.


$.ajax({
type: "POST",
url: "ajaxtest.cfc?method=loginCheck&returnformat=plain",
data: datastring,
success: function(response){
var resp = jQuery.trim(response);//getting alot of whitespace in my return CFC method
if (resp == 'true'){
    $('#loginResponse').html("<span style='color: green;font-weight: bold; font-size: 15px;'>Success!!</span>");
    // you'll want to put your code here to move onto the next page. I would simply do a page refresh
    // and continue with using the session's login data
}else{
    $('#loginResponse').html("<span style='color: red;font-weight: bold; font-size: 15px;'>Failed!!</span>");
}
}
});
What happened here? Let's break this down. RESPONSE is the variable I created to hold the CFC's return value. I could have easily called it "valid" or something like that. But, just wanted to let you know you can name the value coming back to anything you want.

Next up I trim my response. Not sure this is necessary, but my CFC was returning alot of whitespace. Probably unnecessary for everyone else.

Next, I decided to do an IF/ELSE based on the return value.

If resp is TRUE then add to the loginResponse div, the word "Success!!" that's styled within a span tag.
I do the same for a FALSE response.

I hard coded the styling for this example, but you're going to want to add a class to this field.

ajaxtest.cfc:

<cffunction name="loginCheck" access="remote" returntype="string" displayname="validates login">
<cfargument name="email" type="string" required="yes">
<cfargument name="password" type="string" required="yes">

<cfset valid = "">
        
        
<cfquery name="validate" datasource="#variables.dsn#">
select username,password from employees_login
where username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#">
and password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.password#">
</cfquery>
        
<cfif validate.recordcount>
    <cfset valid ="true">
<cfelse>
<cfset valid="false">
</cfif>
        
<cfreturn valid>
</cffunction>
Here's the demo:

jQuery ajax with CF

Comments
Phillip Senn's Gravatar I appreciate you using the .ajax command instead of .get and .put.
I've been playing around with all the return codes.

(function($) {
   $().ajaxStart(function() { // Learning jQuery pg. 129
      $('#busy').slideDown();
   });

   $().ajaxSend(function(myEvent, request, settings) {
      $('#debug').append(myEvent.type+'<br />');
      $('#debug').append('readyState:'+request.readyState+'<br />');
      $('#debug').append('multipart:'+request.multipart+'<br />');
      $('#debug').append('type:'+settings.type+'<br />');
      $('#debug').append('url:'+settings.url+'<br />');
   });

   $().ajaxSuccess(function(myEvent, request, settings) {
      $('#debug').append(myEvent.type+'<br />');
      $('#debug').append('readyState:'+request.readyState+'<br />');
      $('#debug').append('status:'+request.status+'<br />');
      $('#debug').append('responseText:'+request.responseText+'<br />');
      $('#debug').append('type:'+settings.type+'<br />');
      $('#debug').append('url:'+settings.url+'<br />');
   });
   $().ajaxComplete(function(myEvent, request, settings) {
      $('#debug').append(myEvent.type+'<br />');
      $('#debug').append('readyState:'+request.readyState+'<br />');
      $('#debug').append('multipart:'+request.multipart+'<br />');
      $('#debug').append('status:'+request.status+'<br />');
      $('#debug').append('type:'+settings.type+'<br />');
      $('#debug').append('url:'+settings.url+'<br />');
   });

   $().ajaxStop(function() {
      $('#busy').slideUp("slow");
   });

   $().ajaxError(function(myEvent, request, settings, thrownError) {
      $('#debug').append(myEvent.type+'<br />');
      $('#debug').append('readyState:'+request.readyState+'<br />');
      $('#debug').append('multipart:'+request.multipart+'<br />');
      $('#debug').append('status:'+request.status+'<br />');
      $('#debug').append('type:'+settings.type+'<br />');
      $('#debug').append('url:'+settings.url+'<br />');
   });
})(jQuery);
# Posted By Phillip Senn | 3/18/09 7:33 AM
Dan G. Switzer, II's Gravatar Take a look at jQuery's Form plug-in. All you need to do is to hook it to an existing form element and it will automatically post content to the server via AJAX. It handles all the work of the serialization for you. This is definitely the easiest, cleanist way to post a form via AJAX in jQuery. The plug-in has been around forever and even handles things such as file uploads.
# Posted By Dan G. Switzer, II | 3/18/09 8:59 AM
Admin's Gravatar Thanks Dan for that reference. I'll look into the form plug in. Is it this one that you are referring to? http://www.malsup.com/jquery/form/
# Posted By Admin | 3/18/09 1:59 PM
David Levin's Gravatar What happens when you have to pass a more complex variable type like a structure or a query (or a query within a structure?) Can you simply serialize that information as well or do you have to convert it to a WDDX packet first?
# Posted By David Levin | 6/13/09 2:27 PM
admin's Gravatar @David: The only thing I can say is, give it a try. see if it works.
# Posted By admin | 7/9/09 11:07 AM
David Levin's Gravatar As it turns out you can pass complex structures via WDDX and JQuery. The trick is to not have any special characters such as "<" or ">"
ANYWHERE in your variable. For some reason the serializer doesn't escape them properly. Also, because JQuery appears to pass the variables in some
kind of query string format you need to make sure your variables are URL safe as well.

Here is the code I used that seemed to work: (assuming MyStructure is a CF structure object containing strings, numbers, and a query object)

<cfloop collection="#MyStructure #" item="i">
   <cftry>
      <cfset MyStructure [i] = XMLFormat(MyStructure [i])>
<cfset MyStructure [i] = URLEncodedFormat(MyStructure [i])>
<cfcatch type="any"></cfcatch>
</cftry>
</cfloop>

<script type="text/javascript">
<!--- Convert the object into a javascript variable object--->
<cfwddx action="cfml2js" input="#MyStructure #" toplevelvariable="tempParams">

wddxSerializer = new WddxSerializer();
tableParams = wddxSerializer.serialize(tempParams);

... etc... to Jquery stuff...

Hopefully this will help anyone else having problems with passing special characters. :)
# Posted By David Levin | 7/9/09 1:39 PM
Shaun Mccran's Gravatar Hi,
A great run through of passing values directly through to a CFC. I never considered the returnformat value, turns out it was causing me grief.

Also clarified a few points on the AJAX request method for me, now I don't need to use a remote_processor file as a handler.

Thanks
Shaun
# Posted By Shaun Mccran | 8/18/09 9:21 AM
BT's Gravatar SO not that is a success how do you push the user to the correct page?
# Posted By BT | 2/9/10 11:24 AM
Admin's Gravatar Well, after validation on the CF side, it would be wise to set some session variables, say something like, "session.loggedIn = true", or something to that effect. Then on the front-end, after a 'success', you could use a setTimeout function to delay redirect to a customized page (like a portal page).

HTH
# Posted By Admin | 2/9/10 11:53 AM

Calendar

NAVIGATION

Recent Entries

Recent Comments

RSS

Search

Subscribe

Tags