7. Introduction to AHAH in Drupal

Last modified: May 26, 2009 - 19:19

Developers are often confused about AHAH in Drupal. The acronym usually refers to a subset of AJAX functionality. Whilst AJAX usually involves returning an XML document, which needs to be parsed, in AHAH you simply return HTML ready to be loaded into a DOM element of choice.

In Drupal, however, AHAH has a particular meaning. It all started with the AHAH Forms Framework module for Drupal 5, the purpose of which was to allow developers to add new form elements to a form without reloading the page. By adding an '#ahah' property to a form element, say a button, specifying the callback function that would build the new elements, the effect (e.g. fade or slide) you wanted, and the event on which your callback should be called (defaulting to 'click'), your button would deliver the new elements as soon as user clicked the button, without need to write single line of JavaScript.

The functionality was later incorporated into Drupal 6, and this is why the term AHAH now refers exclusively to the dynamic rendering of form elements in Drupal. If you are just looking to load some normal content (as opposed to form elements) dynamically, then AHAH, in this Drupal sense, is not the right tool for you - have a look at section 6 of this guide, AJAX in Drupal using jQuery. In fact, the difference that originally led to the coining of the term AHAH - that it didn't involve XML, whereas AJAX did - is no longer considered significant and it's pretty much all referred to as AJAX these days.

For the special case that is AHAH in Drupal, while it is true that this built-in functionality eliminates the need for you to write your own js to achieve dynamically loaded elements, there are a number of important steps that can be tricky, the most significant being the callback function, which is discussed in the subsection, Doing AHAH Correctly in Drupal 6. The more basic steps are best explained by example, so let's have a look at how it's done in Poll module. The poll creation form has a "More choices" button which, when clicked, dynamically adds a new set of poll choice fields (one field for the text and one field for the initial number of votes). Here's how the AHAH is set up in the form:

<?php
// the following code is from the poll_form() function in poll.module

  // Add a wrapper for the choices and more button.
 
$form['choice_wrapper'] = array(
   
'#tree' => FALSE,
   
'#weight' => -4,
   
'#prefix' => '<div class="clear-block" id="poll-choice-wrapper">',
   
'#suffix' => '</div>',
  );

 
// Container for just the poll choices.
 
$form['choice_wrapper']['choice'] = array(
   
'#prefix' => '<div id="poll-choices">',
   
'#suffix' => '</div>',
   
'#theme' => 'poll_choices',
  );

 
// Add the current choices to the form.
 
for ($delta = 0; $delta < $choice_count; $delta++) {
   
$text = isset($node->choice[$delta]['chtext']) ? $node->choice[$delta]['chtext'] : '';
   
$votes = isset($node->choice[$delta]['chvotes']) ? $node->choice[$delta]['chvotes'] : 0;

   
$form['choice_wrapper']['choice'][$delta] = _poll_choice_form($delta, $text, $votes);
  }

 
// We name our button 'poll_more' to avoid conflicts with other modules using
  // AHAH-enabled buttons with the id 'more'.
 
$form['choice_wrapper']['poll_more'] = array(
   
'#type' => 'submit',
   
'#value' => t('More choices'),
   
'#description' => t("If the amount of boxes above isn't enough, click here to add more choices."),
   
'#weight' => 1,
   
'#submit' => array('poll_more_choices_submit'), // If no javascript action.
   
'#ahah' => array(
     
'path' => 'poll/js',
     
'wrapper' => 'poll-choices',
     
'method' => 'replace',
     
'effect' => 'fade',
    ),
  );
?>

First, it creates a wrapper to hold all of the ahah elements, including the button itself. Then it creates a wrapper specially for the choices themselves; all existing choices are added inside this wrapper; then in the #ahah property of the button element ($form['choice_wrapper']['poll_more']) you'll see this wrapper is referenced. In effect, what the #ahah property is saying here is "Fetch new elements from the path 'poll/js', stick them into the div with the id of 'poll-choices', replacing the existing contents of that div (as opposed to appending to them, which is another option), and use the 'fade' effect when making the switch; and do all of this when a user clicks me". Other options would be, for example, to have the behavior bound to the change event of a dropdown element, instead of the click event of a button (in this case, you would add the 'event' parameter to your '#ahah' property and set its value to 'change'), or to have a different effect instead of 'fade'.

The code in misc/ahah.js looks after the jQuery side of things (binding the desired behavior to your element and making the ajax request to your specified callback) and now what you need to do is create your callback function and your submit handler and make sure your form-building function is built correctly. See the subsection, Doing AHAH Correctly in Drupal 6 for an explanation of how to avoid the many pitfalls you could fall into at this juncture.

minor fix

Pasqualle - December 24, 2008 - 14:50

according to http://api.drupal.org/api/file/developer/topics/forms_api_reference.html the submit type does not have a #description property.

It probably should be changed to:

'#attributes' => array('title' => t("If the amount of boxes above isn't enough, click here to add more choices.")),

...

Caleb G - October 16, 2009 - 19:50

I *really* appreciate that this post points out that the context in which Drupal uses the term "AHAH" bears no relation to the context that "AHAH" is normally used in. IMHO, this situation should be changed in and not just footnoted since it is so likely to be the source of confusion for newcomers to Drupal/AHAH.

UPDATE: From Katherine Bailey (acknowledge Drupal/AJAX/AHAH ninja), "thankfully that misnomer will fall by the wayside in D7 - it's all just ajax, including dynamically rendering form elements".

 
 

Drupal is a registered trademark of Dries Buytaert.