Multi-dependent select elements in Drupal 7 using ajax

Profile picture for user Phil Frilling
By Phil Frilling, 31 December, 2013
Recently I needed to modify a Drupal 7 node form to have two drop down select elements populate based upon a third select element's choice. I have altered select elements in the past to have a single dependency, but never have I made one element control the content of two different elements. To start, I made the first element control the second (the old familiar way): I need the selection in field_dropdown_1 to dictate what appears in the list for field_dropdown_2 and field_dropdown_3. To start, I used hook_form_alter() to add the #ajax functionality to field_dropdown_1 like so:

$form['field_dropdown_1'][LANGUAGE_NONE]['#ajax'] = array(
    'callback' => 'my_custom_callback',
    'wrapper' => 'my-wrapper-div-1',
  );

/**
 Logic to get the options of field_dropdown_2 would go here.
**/
Next, I added my callback function for the ajax element:

function my_custom_callback ($form, $form_state) {
  return $form['field_dropdown_2'];
}
The code above gave me a single dependent select element. Now, how do we add the second dropdown?

Solution

After reading the form API reference regarding the #ajax property: https://api.drupal.org/api/drupal/developer!topics!forms_api_reference…, I discovered that the ajax callback expects HTML OR an array of ajax commands to execute. This discovery led me to the ajax_command_replace() function: https://api.drupal.org/api/drupal/includes!ajax.inc/function/ajax_comma…. So, as it turns out, to modify two select's with one ajax call we just needed to modify our custom callback function to return ajax commands like this:

$result = array(
    '#type' => 'ajax',
    '#commands' => array(
      ajax_command_replace('#my-wrapper-div-1', drupal_render($form['field_dropdown_2'])),
      ajax_command_replace('#my-wrapper-div-2', drupal_render($form['field_dropdown_3'])),
    ),
  );
  return $result;
This change in the callback function returns two ajax replace commands, one for field_dropdown_2 and a second for field_dropdown_3. Thanks to these two comments for helping me get the callback correct: https://api.drupal.org/comment/50903#comment-50903 https://api.drupal.org/comment/51178#comment-51178