JavaScript, AJAX, AHAH API

Last modified: March 25, 2009 - 17:39

The core Drupal js file creates a Drupal Object with a few properties that modules can use, like Drupal.behaviors, Drupal.settings, etc.
The very first line of JavaScript code in Drupal core, in drupal.js, is an Object declaration:

var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} };

In this code, Drupal is an Object declared to be equal to itself, or, if not yet set, equal to { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} } which is an Object containing 4 properties (settings, behaviors, themes, and locale) each of which is itself an Object. This line of code is an Object Initializer. This Drupal object and its properties can then be used and extended by other modules. The best way to understand this is to look at the different properties one by one and the ways they are used by Drupal modules.

Drupal.settings

Drupal.settings is what enables us to pass information from our PHP code to our JS code. This means you can change how your JavaScript behaves based on how your module is configured, for example, or you may want to simply let JavaScript know what the base path is. You just create a PHP array of settings, as follows:

$my_settings = array(
  'basepath' => $base_path,
  'animation_effect' => variable_get('effect', 'none')
);

Then call drupal_add_js() and pass in this array, with "setting" as your second parameter:
drupal_add_js(array('my_module' => $my_settings), "setting");

Note that it is further padded inside another array purely for namespacing purposes: another module might define the basepath setting as well. Now you can access these settings in your JS code as follows:
var basepath = Drupal.settings.my_module.basepath;
var effect = Drupal.settings.my_module.animation_effect;

Drupal.behaviors

When most of us learn jQuery for the first time, we learn to put all our code inside the $(document).ready function, like this:

$(document).ready(function(){
// do some fancy stuff
});

This ensures that our code will get run as soon as the DOM has loaded, manipulating elements and binding behaviours to events as per our instructions. However, as of Drupal 6, we don't need to include the $(document).ready() function in our jQuery code at all. Instead we put all our code inside a function that we assign as a property of Drupal.behaviors. The Drupal.behaviors object is itself a property of the Drupal object, as explained above, and when we want our module to add new jQuery behaviours, we simply extend this object. The entire jQuery code for your module could be structured like this:

Drupal.behaviors.myModuleBehavior = function (context) {
//do some fancy stuff
};

Any function defined as a property of Drupal.behaviors will get called when the DOM has loaded
drupal.js has a $(document).ready() function which calls the Drupal.attachBehaviors function, which in turn cycles through the Drupal.behaviors object calling every one of its properties, these all being functions declared by various modules as above, and passing in the document as the context.

The reason for doing it this way is that if your jQuery code makes AJAX calls which result in new DOM elements being added to the page, you might want your behaviours (e.g. hiding all h3 elements or whatever) to be attached to that new content as well. But since it didn't exist when the DOM was loaded and Drupal.attachBehaviors ran it doesn't have any behaviours attached. With the above set-up, though, all you need to do is call Drupal.behaviors.myModuleBehavior(newcontext), where newcontext would be the new, AJAX-delivered content, thus ensuring that the behaviours don't get attached to the whole document all over again. There are full instructions on how to use this code on the Converting 5.x modules to 6.x page.

This usage is not in fact exclusive to Drupal 6: the jstools package in Drupal 5 uses this exact pattern to control the behaviours of its modules - collapsiblock, tabs, jscalendar, etc.

 

The Drupal.theme function

Drupal.theme() is the client-side counterpart to the server-side theme() function. Here's what it looks like:

Drupal.theme = function(func) {
for (var i = 1, args = []; i < arguments.length; i++) {
  args.push(arguments[i]);
}
  return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
};

So, when you make a call to Drupal.theme(), you pass in a function name as your first argument and all subsequent arguments will be arguments to be passed to that function. The function you pass in will need to be a prototype object of Drupal.theme, an example of which is below:
Drupal.theme.prototype.myThemeFunction = function (left, top, width) {
  var myDiv = '<div  id="myDiv" style="left:'+ left +'px; top:'+ top +'px; width:'+ width +'px;">';
  myDiv += </div>';
  return myDiv;
};

And here's how you would call it:
Drupal.theme('myThemeFunction', 50, 100, 500);

See here for the official documentation on this.

Drupal.locale

The Drupal.local property works in conjunction with Drupal.t, the JS equivalent of the server-side t() function. It holds a collection of string translations so that Drupal.t can then access the required string from Drupal.locale in order to
translate what was passed into it.

Further information:

 
 

Drupal is a registered trademark of Dries Buytaert.