WorkHabit Blogs
WORKHABIT LABSDrupal + AJAX, Part 1
Some months ago, I discussed multiple values in CCK using AJAX. A few people showed interest, so here's Part 1 of how AJAX can go together with Drupal.
We'll start with a common use case: checking that a username is available when a new user signs up. After you're done with this tutorial, you should be able to give the new user near-instant feedback on whether or not their username is available. I like to start at my desired result and work backwards, so that's what we'll do.
Let's create a module called demo_user.module and begin!
Step 1: Alter the user registration form to include a result field
The desired result here is to show the user whether or not their desired username is available, so let's alter the registration form to give us a div to place our results in.
/**
* Implemetation of hookformalter()
*/
function demouserformalter($formid, &$form) {
if ($formid == 'userregister') {
$usernameverifyresult = '';
$form['account']['name']['#suffix'] = $usernameverifyresult;
}
}
This might actually be the trickiest part. If you have a custom registration form, you'll need to modify this implementation to suit your particular situation.
Step 2: Write a menu hook
The next thing we want to do is put together the logic that actually accomplishes our task. In this case, our task is to see if a given username is already taken. First, write a menu hook like so:
/**
* Implemetation of hookmenu()
*/
function demousermenu($maycache){
$items = array();
if (!$maycache) {
$items[] = array(
'path' => 'user/usernamecheck',
'title' => 'username check',
'callback' => 'demouserusernamecheck',
'callback arguments' => array($GET['username']),
'access' => true,
'type' => MENUCALLBACK,
);
}
return $items;
}
This callback will take the username we pass in with GET (more on that later) and shoot it over to a function called demouserusername_check(). (Note: don't forget to change the 'access' key to something appropriate for you!)
Step 3: Write some logic to compare the requested user name to what's already in the database. We can check to see if the requested username is already taken with a simple sql query: SELECT name FROM users WHERE name = $requested_name (Note: if your users table is case-sensitive (this is rare), you might want to change the query to a LIKE) This function takes the result of the check, and generates the appropriate user-facing response. I've used two graphics here, cross.gif for a failure and check.gif for success:
/**
* ajax user name check.
*
* Checks for the availability of a given username.
* @author Domenic Santangelo
* @param string $username The desired username
* @return string HTML-ified result of the check.
*/
function demouserusernamecheck($username) {
$result = dbresult(dbquery("SELECT name FROM {users} WHERE name = '%s'", $username));
if($result) {
$icon = "cross.gif";
$msg = "It looks like this username is already on record. Do you want to retrieve your password?";
}
else {
$icon = "check.gif";
$msg = "Thanks!";
}
echo "{$msg}";
}
Notice that even though we're throwing user-generated strings into a sql query (a potentially dangerous operation), dbquery() automatically escapes the string with dbescapestring() via dbquery_callback().
STEP 4: Wire the callback into JavaScript Now let's write a JavaScript function that will handle passing the requested username to our callback. This is how we can get the asynchronous request to work. I like to have a little spinner graphic to show that the check is processing, so I stuck a graphic called spinner.gif in /sites/all/themes/mysite/images/. Now, using the magic of JQuery:
function usernameCheck(obj) {
//Spinner shows while the ajax call does its thing
$('#usernameresult').html('Validating your username...');
$('#usernameresult').slideDown();
//Callback function that inserts the result of the username check in the div we set up in Step 1 function domCallback(msg) { $('#usernameresult').html(msg); $('#usernameresult').slideDown(); }
//Actually perform the call $.ajax({ type: "GET", url: '/user/usernamecheck', data: "username="+obj.value, success: function(msg){ domCallback(msg); } }); } Stick this little function into a .js file that gets loaded on your site — either on the registration page only, or sitewide, whatever… just be sure it's there!
STEP 5: Wire the JavaScript function into the Username field on the registration page Let's go back to our hookformalter() implementation and let the form field know that we should fire the username check when the user enters a name and tabs/clicks out of the field
/**
* Implemetation of hookformalter()
*/
function demouserformalter($formid, &$form) {
if ($formid == 'userregister') {
$usernameverifyresult = '';
$form['account']['name']['#suffix'] = $usernameverifyresult;
$form['account']['name']['#attributes'] = array('onblur' => 'usernameCheck(this)'); //added the call to our JS function
}
}
STEP 6: Theming
You'll want to theme this all to be appropriate to your site. I don't have any magic sauce for you on this one, but it should be a straightforward task.
Grats, you've implemented a rad-looking ajax username checker!


In response to the comment
In response to the comment left at http://www.workhabit.org/multiple-form-values-cck-huge-problem#comment-752
Hey! Thanks for reading, glad it was useful.
Regarding $form, it all depends on the structure of your own registration form. If, for example, your account field is NOT in a field group, $form[‘name’][‘#suffix’] would be correct.
Your point about the GET url in the javascript is correct as well.
About the validation graphic, yes it will disappear very quickly if you’re working locally! I wouldn’t bother with a sleep(), since there will be some latency when you push it live. What I do is style the #suffix with display: none; in CSS (which is why the JS callback has $(‘#username_result’).slideDown(); in it). It has looked okay for me =)
Another question
Fine!
About $form, I’ve used a clean Drupal 5.7 install, so I think I’ve used the default user form registration (didn’t alter any fieldset).
And the question, about the time of validation graphic, how you would do the call to the “ok-wrong” ajax function if you want to do that only after the php validation ends? This way you’ll be always sure that the graphic stays there time enough and users will be able to see it.
Thanks again for the tutorial, hope you do some more on this subject! cambrico.net
Forms Validation
Hey guys, its Brendon here. In light of this post I wanted to hit you up with my Drupal AJAX Validation module. Check it out and let me know what you think..
http://drupal.org/project/ajax_validation
in the hook_menu() return
in the hook_menu() return $items; is missing. That costs me 2 hours als drupal newbie.
This snippet (taken from the
This snippet (taken from the main post):
$.ajax({ type: "GET", url: '/user/usernamecheck', data: "username="+obj.value, success: function(msg){ domCallback(msg); } });should ensure that the ok/wrong graphic only appears once the ajax call is complete. (“success:” refers to the success of the ajax request). Are you working on a remote server or locally? If you’re working locally, it will go really quickly.
Hi again! I've packed all
Hi again!
I’ve packed all this with some modifications (to make it work through hide() and show()) and I’ve blogged it, you can take a look (it’s in spanish, sorry :)) here:
http://cambrico.net/04-05-2008/taller-de-drupal-y-ajax-comprobar-si-un-nombre-de-usuario-esta-registrado
The direct link to the module is this:
http://cambrico.net/sites/cambrico.net/files/demo_user.zip
Thanks! http://www.cambrico.net
Yikes! Sorry about that!
Yikes! Sorry about that! Fixed above.
Post new comment