Dependent Lists and Ajax Form Submission
In this post we going to demo how simple it is to create dynamic forms with Drupal 7 Form API (aka FAPI).
Our form will have 2 select lists (aka drop down combo boxes). Our first list lets a user select a US State. Once a state has been selected, we dynamically render a "city" select list. The city select list only contain cities for the selected state.
We will include a submit button, however the form will be submitted asynchronously (aka via AJAX).
Upon submission, we will asynchronously render a short message. The message tells the user which city they just submitted.
Here is our form in it's initial state:

Here is our form after a user selects a state:

Finally, here is our form after the submit button is clicked:

Now our code. Let's start with the form definition. We are creating a separate select list for Illinois and a separate select list for Ohio. We add a '#states' array directive to both the Illinois and Ohio lists. The '#states' array directive controls whether a list is displayed or hidden depending on what value is selected in the parent list (state_list). "':input[name="state_list"]" is a JQuery expression.
You should also note the directives we added to our submit button element. We explicitly turn off the normal synchronous submit (i.e. full page repaint) by using "'#executes_submit_callback' => FALSE". Instead we submit asynchronously with '#ajax' => array('callback' => 'advanced_form_callback', 'wrapper' => 'status',)'.
Our form definition:
function advanced_form($form, &$form_state) { $form['status'] = array( '#type' => 'markup', '#prefix' => '<div id="status">', '#suffix' => '</div>', '#markup' => '', ); $form['state_list'] = array( '#type' => 'select', '#title' => 'Choose A US State First', '#options' => array(0 => 'Choose', 1 => 'Illinois', 2 => 'Ohio'), '#default_value' => 0, ); $form['illinois_cities'] = array( '#type' => 'select', '#description' => t("Cities in Illinois."), '#states' => array( 'visible' => array( ':input[name="state_list"]' => array('value' => '1'), ), ), '#options' => array(0 => 'Chicago', 1 => 'Evanston', 2 => 'Springfield'), '#default_value' => 0, ); $form['ohio_cities'] = array( '#type' => 'select', '#description' => t("Cities in Ohio."), '#states' => array( 'visible' => array( ':input[name="state_list"]' => array('value' => '2'), ), ), '#options' => array(0 => 'Cleveland', 1 => 'Akron', 2 => 'Grantsville'), '#default_value' => 0, ); $form['submit'] = array( '#type' => 'submit', '#value' => 'Submit', '#executes_submit_callback' => FALSE, '#ajax' => array( 'callback' => 'advanced_form_callback', 'wrapper' => 'status', ), ); return $form; }
Now our callback. We simply inspect what the user selected and return the name of the city. I added a little helper function called "form_result_helper" to navigate through the $form_state structure (source below).
function advanced_form_callback($form, &$form_state) { $city_name = form_result_helper($form_state); $element = $form['status']; $element['#markup'] = t('You submitted @city', array('@city' => $city_name)); return $element; }
Our helper function:
function form_result_helper($form_state) { $us_state = $form_state['values']['state_list']; $city_name = t('No City Selected'); $city = ''; switch ($us_state) { case 1 : $city = $form_state['values']['illinois_cities']; switch($city) { case 0: $city_name = 'Chicago'; break; case 1: $city_name = 'Evanston'; break; case 2: $city_name = 'Springfield'; break; } break; case 2 : $city = $form_state['values']['ohio_cities']; switch ($city) { case 0: $city_name = 'Cleveland'; break; case 1: $city_name = 'Akron'; break; case 2: $city_name = 'Grantsville'; break; } break; } return $city_name; }
That's it. Two dependent drop down lists, and a Ajax submission. Drupal 7 makes it really easy.



