Adding additional form elements using ahah_helper in Drupal 6

This tutorial will show you how to add new form elements which will be available in $form_state['values'] once the form has been submitted using a submit button by taking advantage of the AHAH helper module.

The AHAH helper module does provide a demo, but the demo shows how to change a few fields depending on a selection made from a select element. The tutorials I looked at online either didn't cover the issue properly or just didn't work.

Currently the 6.x-2.0 release throws up errors if you are using certain PHP versions, but these are gone in the 6.x-2.x-dev release.

Scenario

You want the user to enter in some data, lets say their favourite car. But you want the ability for them to add as many cars as they want if they have more than one.

Code

Firstly you will need to set up a menu callback for your form, but I will assume you know how to do this if you are looking at this tutorial.

We will set up the basic form first, this includes one textfield and a submit button to submit the form with the textfield in a wrapper (this is important later on for the ahah_helper module).

<?phpfunction test_form($form_state NULL) {
  
$form['cars'] = array(
    
'#type' => 'fieldset',
    
'#title' => t('Favourite cars(s)'),
    
'#prefix' => '<div id="favourite-cars-wrapper">',
    
'#suffix' => '</div>',
  );
  
$form['cars']['car'] = array(
    
'#type' => 'textfield',
    
'#title' => t('Favourite car'),
    
'#size' => 36,
    
'#default_value' => $form_state['values']['car'],
  );
  
$form['submit'] = array(
    
'#type' => 'submit',
    
'#value' => t('Submit'),
  );
  return 
$form;
}
?>

This is very basic and allows the user to enter one car and submit the form. We now need to add in the extra functionality of ahah_helper to be able to add mulitple fields.

<?phpfunction test_form($form_state NULL) {
  
  
ahah_helper_register($form$form_state); // Absolutely vital for ahah_helper to do it's job

  // We check to see if quantity has been set, ie if the form has been submitted yet.  If not, we show 1 field, you can change this to however many fields you want to show up as default.
  if (!isset($form_state['storage']['quantity'])) {
    
$quantity 1;
  }
  else {
    
// If the form has been submitted we get the quantity that was stored.
    
$quantity $form_state['storage']['quantity'];
    
// We then do a check to see if the user has clicked the "Add another car" button, if they have we increase the amount by 1.
    
if (isset($form_state['values']['cars']['add_more']) && $form_state['values']['op'] == 'Add another car') {
      
$quantity++;
    }
  }

  // We create a hidden form element to store the amount of fields that the user has added.
  
$form['quantity'] = array(
    
'#type' => 'value',
    
'#value' => $quantity,
  );

  $form['cars'] = array(
    
'#type' => 'fieldset',
    
'#title' => t('Favourite cars(s)'),
    
'#prefix' => '<div id="favourite-cars-wrapper">',
    
'#suffix' => '</div>',
    
'#tree' => TRUE // This is important for ahah_helper.
  
);
  
// We now do a simple loop, creating however many textfields are defined by $form_state['storage']['quantity']
  
for ($i 1$i <= $quantity$i++) {
    
// The element name needs to be different for each textfield, otherwise we will only get one value after the form is submitted.
    
$form['cars']['car_'$i] = array(
      
'#type' => 'textfield',
      
'#title' => t('Favourite car'),
      
'#size' => 36,
      
'#default_value' => $form_state['values']['cars']['car_'$i],
    );
  }

  // We add in a button with the #ahah element which will handle all our work for us.
  
$form['cars']['add_more'] = array(
    
'#type' => 'submit',
    
'#value' => t('Add another car'),
    
'#ahah' => array(
      
'event' => 'click'// When the button is "clicked", AHAH will do it's job
      
'path' => ahah_helper_path(array('cars')), // The array features the wrapper form field. So our form wrapper is $form['cars'], so we set this to array('cars'). If your form was $form['cars']['another_wrapper'], the path would be array('cars', 'another_wrapper').
      
'wrapper' => 'favourite-cars-wrapper'// We then define the wrapper which will be changed.
    
),
  );
  
$form['submit'] = array(
    
'#type' => 'submit',
    
'#value' => t('Submit'),
  );
  return 
$form;
}
?>

So what have we done...first we added the following line:

<?phpahah_helper_register($form$form_state);?>

This is a vital function that needs to be present in your form for ahah_helper to do it's job.

Next we check to see if the form has been submitted before and if it has, get the amount of textfields that the form had by storing it in a hidden field. We then do a further check to find out what button was clicked. If the "add more" button was clicked, then we add another textfield by increasing the value of the quantity variable.

A minor, but very important change we make is adding '#tree' => TRUE to our wrapper element, this is a requirement for ahah_helper to do it's job properly.

Next we use a for loop, to add all our textfields into the form. This should be self-explanitory but will go in to a bit more depth further on when we talk about the #ahah element.

We added an additional button to the form, this is so that the user can add another field to the form. You don't need to worry about javascript degradation as ahah_helper takes care of this.

One attribute of #ahah on the button that isn't listed in the form, but is very important, is the "method". The default value of this is replace, which is what we want. This replaces the whole contents of the wrapper which we define with the data from the path which we defined. This is why we needed the for loop to recreate the textfields.

To take care of the form when javascript is disabled, you must check which button was pressed when the form was submitted.

<?phpfunction test_form_submit($form$form_state) {
  if (
$form_state['values']['op'] == 'Submit') {
    
drupal_set_message('Submit button clicked');
  }
  else {
    
drupal_set_message('Add more button clicked');
  }
}
?>

With javascript enabled, when clicking the Add more button, Drupal will perform validation on the form, but will not submit the form. Whereas clicking the submit button will perform validation and submit the form.