Implementing AJAX in Drupal
Implementing AJAX in Drupal

In my opinion, the AJAX (Asynchronous javascript and xml) technology has been a real boost to the application of javascript. Traditionally,javascript adds enhancements to a webpage by providing a rich user experience, client-side form validation and submission, and a whole bunch of nifty things:believe me ,javascript is powerful :) A traditional limitation of javascript had been the lack of direct interaction with a server:AJAX to the rescue!Thus,with AJAX, we can query a server for data and add the data to a webpage without reloading the page!Now, that's simply awesome!

The good news is Drupal 6 has native AJAX support. To illustrate this I'll use a form with two textfields in which entering value in one textfield populates the other textfield with a value fetched from a database through AJAX.

Let's assume we have we have a database with a table named color_table, which contains a two columns,'country' and 'color_rep',for a country's color representation (each country has one color).

Now to the form:

function colors_form(){
$path = drupal_get_path('module','mycolors');
drupal_add_js($path.'/color.js');
$form['country'] = array(
'#type'=>'textfield',
'#title'=>t('Name of country')
);
$form['color']=array(
'#type'=>'textfield',
'#title'=>t('Color Representation')
);
$form['submit'] = array(
'#type'=>'submit',
'#value'=>t('Submit')
);
return $form;
}

The above code is a simple form in drupal. First of all, we are implementing this function in a module called mycolors.
The lines that add the ajax(javascript) functionality to this form are:

$path = drupal_get_path('module','mycolors');
drupal_add_js($path.'/color.js');

The first line gets the path of the module in the file system and the second tells drupal to add a javascript file color.js(which we have not yet created), located within the module folder, to the form.

To make a request to the server(and hence our database) for a country's color representation, we need to define a function that handles just that. Here we go :

function colors_form_ajax($country){
$query = "SELECT * FROM {color_table} WHERE country = '%s'";
if($result = db_query($query,$country)){
echo drupal_json(array('response'=>$result->color_rep));
exit;
}
}

The function above does two main things.First, it queries the database,specifically, the color table based on it's argument, and then returns a JSON(Javascript Object Notation) version of the response by calling the inbuilt function drupal_json.

Now that we have the form and the function that queries the server, we ask, how do we link the two? Simple!drupal's menu system.
Lemme delve a bit into the workflow here.
When a user types into the 'Name of country' textfield in our form, the javascript file,color.js, takes the value in the textfield and places a request to a certain menu path,which should then call our 'colors_form_ajax' function,thus returning a JSON version of the response.

So on to our menu:

function mycolor_menu(){
$items = array();
//menu item for our form
$items['colorform'] = array(
'title'=>t('Determine country\'s color'),
'page callback'=>'drupal_get_form',
'page arguments'=>array('colors_form'),
'page arguments'=>TRUE,
'type'=>MENU_NORMAL_ITEM
);
//menu item for the function that queries the database
$items['getcolor/%'] = array(
'page callback'=> 'colors_form_ajax',
'page arguments'=>array(1),
'type'=>MENU_CALLBACK
);
return $items;
}

Some things to note about the code above:
The menu item of the form is denoted to be of the type 'MENU_NORMAL_ITEM'.This means that this menu item will be shown in the navigation block or wherever it's specified to show. The menu item for the function that queries the database on the other hand, is of the type 'MENU_CALLBACK'.This means that this menu will only be called upon request by other parts of the system,as it cannot be seen(and hence clicked) by any user.Also, note the '%' character and the 'page arguments' set to array(1) in the menu definition.It tells drupal to set whichever value,that is appended to the url 'getcolor' to be used as the argument to the function 'colors_form_ajax'.We'll revisit this in the javascript file color.js.

Now to the javascript file.I chose to implement the javascript using jquery, a javascript library, mainly because drupal provides native jquery support and it's cross-platform as well.(You can find more on jquery at http://jquery.com).
The code in our javascript file, color.js looks like this:

Drupal.behaviors.mycolors = function(context){
// when the value in the 'Name of country' textfield changes
$("#edit-country").change(function(){
var chosenCountry = $(this).val();
//function that sets value of the color field when
// a response is obtained
var setColor = function(data){
var response = Drupal.parseJson(data);
$("#edit-color").val(response.color_rep);
}
// path to make the ajax call to
var ajaxPath = 'getcolor/' + chosenCountry;
// making a call to the menu path that will call
// the function that queries the server
$.post(ajaxPath,null,setColor);
return false;
});
});

Here are some things to note about the code above:
The line
Drupal.behaviors.mycolors = function(context)
is equivalent to jquery's $(document).ready() and does the same thing: ensuring that the code fires as soon as the document or 'page' is ready, even though images and other things may not have been loaded completely.
NB: Always remember to follow behaviors with your module's name,mycolors in this case. Leave the 'context' thing untouched.

In drupal, the ids of form elements are preceded by the word edit, so our textfield named country would have the it's id to be edit-country'. Having said that, the next two lines of code get the value entered in the 'Name of country' textfield,anytime the value changes:

$("#edit-country").change(function(){
var chosenCountry = $(this).val();

Next, a function is defined (set to the variable setColor) that parses the response from the server and makes that the value of the 'color' textfield as shown by these lines of code:

var setColor = function(data){
var response = Drupal.parseJson(data);
$("#edit-color").val(response.color_rep);
}

Recall that in the function that queries the server(colors_form_ajax),the $result JSON that was returned had a 'color_rep' attribute,which is referred to in the code snippet above.

We then set the path for the ajax call. Note that this path is the same as the menu path for the function that queries the server for results, and that we add the value in the 'Name of country field' to the path url so that the name will be passed as argument to the function that queries the server as seen in:

var ajaxPath = 'getcolor/' + chosenCountry;

Lastly, we implement the actual ajax call with:

$.post(ajaxPath,null,setColor);
return false;

Note that we passed the second argument as null because we are not sending any separate value. In our case, the value has already been added to the url(ajaxPath).
You should now have a working AJAXified module in drupal!
Cheers.

From carl.blay@suuch.com on Mon, 06/21/2010 - 16:43