Drupal 7: Need to Create Form Fields Dynamically?

We did, when working on the JI QuickBooks module, see the code below to see how we did it.

Background information

How can we program Drupal to create a set of three (or more) fields by just clicking a button? More importantly, when this form is submitted, how is the data accessed using $form_state['values']? Easy, right? Don't go looking in the Example module. Better solution came from a stackoverflow.com post, even though it needed a little bit of work. Let's see the modified version below:

 

function hook_form_alter($form, &$form_state) {
  $form['agencies'] = array(
    '#type' => 'fieldset',
    '#title' => 'Tax Agency',
    '#prefix' => '<div id="replace-this">',
    '#suffix' => '</div>',
    '#tree' => TRUE,
  );

  // Build the initial fields if this is not being rebuilt 
  // from ajax request.
  if (!array_key_exists('clicked_button', $form_state)) {
    create_form($form, 0);
  }
  else {
    // Otherwise add the fields for each existing value.
    foreach ($form_state['values']['agencies'] as $i => $value) {
      create_form($form, $i);
    }

    // Add the additional fields for a new entry.
    $last = count($form_state['values']['agencies']);
    create_form($form, $last);
  }

  $form['add_more'] = array(
    '#type' => 'button',
    '#value' => t('Add More'),
    '#ajax' => array(
      'callback' => 'ajax_simplest_callback',
      'wrapper' => 'replace-this',
      'method' => 'replace',
    ),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  $form['#submit'][] = 'my_form_add_more_submit';

  return $form;
}

function create_form(&$form, $row, $default_values = array()) {
  $form['agencies'][$row] = array('#type' => 'fieldset');
  $form['agencies'][$row]['component_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Component name'),
    '#parent' => 'test',
    '#default_value' => isset($default_values['component_name']) ? $default_values['component_name'] : '',
  );
  $form['agencies'][$row]['agency_name'] = array(
    '#type' => 'select',
    '#title' => t('Select'),
    '#parent' => 'test',
    '#options' => array('1' => 'One', '2' => 'Two', '3' => 'Three'),
  );
  $form['agencies'][$row]['agency_id'] = array(
    '#type' => 'hidden',
    '#default_value' => isset($default_values['agency_id']) ? $default_values['agency_id'] : '',
  );
  $form['agencies'][$row]['agency_rate'] = array(
    '#type' => 'textfield',
    '#title' => t('Rate'),
    '#parent' => 'test',
    '#default_value' => isset($default_values['agency_rate']) ? $default_values['agency_rate'] : '',
  );
}

function ajax_simplest_callback($form, &$form_state) {
  return $form['agencies'];
}

function my_form_add_more_submit($form, &$form_state) {
  dpm($form_state['input']);
  dpm($form_state['values']);
}

Copy and paste the above code and you'll be able to test and learn how it works.  I don't like to give long explanations on how each part functions since most of that is located on the internet. This post is for seasoned Drupal programmers that need a quick answer.

NOTE: dpm() is used in my_form_add_more_submit(). You can download the devel module here, which includes dpm() functions.

Leave a comment