I'm working on a D7 custom form with AJAX dependent dropdown, and I can't figure how to update two fields based on a selection from the first field. Here's the code so far:
/**
* Implements hook_form().
*
* Form builder function for export form
*/
function mymodule_form($node, &$form_state) {
$form = array();
// Get list of available entity types.
$entity_options = array('commerce_product' => t('Product'), 'node' => t('Node'));
$selected_entity_type = isset($form_state['values']['entity_type']) ? $form_state['values']['entity_type'] : key($entity_options);
$form['entity_type'] = array(
'#type' => 'select',
'#title' => t('Entity Type'),
'#description' => t('Select the desired entity type'),
'#options' => $entity_options,
'#default_value' => $selected_entity_type,
'#ajax' => array(
'callback' => 'mymodule_dependent_dropdown_callback',
'wrapper' => 'bundles-replace'
),
);
if ($selected_entity_type == 'commerce_product') {
$bundle_options['product'] = t('Product');
}
else {
// Get available node types.
$node_types = node_type_get_types();
$bundle_options = array();
// Create an array to populate the node options.
foreach($node_types as $type) {
$bundle_options[$type->orig_type] = $type->name;
}
}
$bundle_options = _mymodule_get_bundles($selected_entity_type);
// Get the $selected_bundle based on the entity field. Since there are multiple dependent fields in
// this form, we can't really depend on $form_state['values'].
$selected_bundle = isset($form_state['triggering_element']) && $form_state['triggering_element']['#name'] == 'bundle'? $form_state['triggering_element']['#value'] : key($bundle_options);
$form['bundle'] = array(
'#type' => 'select',
'#title' => t('Bundle'),
'#description' =>t('Select the content type to export'),
'#options' => $bundle_options,
'#default_value' => $selected_bundle,
'#ajax' => array(
'callback' => 'mymodule_dependent_dropdown_callback',
'wrapper' => 'fields-replace'
),
'#prefix' => '<div id="bundles-replace">',
'#suffix' => '</div>',
);
$field_options = _mymodule_get_fields($selected_entity_type, $selected_bundle);
$form['fields'] = array(
'#type' => 'checkboxes',
'#title' => t('Fields'),
'#prefix' => '<div id="fields-replace">',
'#suffix' => '</div>',
'#options' => $field_options
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Export'),
);
return $form;
}
/**
* Since the controlling logic for populating the form is in the form builder
* function, all we do here is select the element and return it to be updated.
*
* @return array
* Renderable array (the second dropdown)
*/
function mymodule_dependent_dropdown_callback($form, $form_state) {
// The returned field depends on the triggering form field.
switch ($form_state['triggering_element']['#name']) {
case 'bundle':
return $form['fields'];
break;
case 'entity_type':
return $form['bundle'];
break;
}
}
/**
* Helper function to populate the fields dropdown.
*
* @param string $key
* This will determine which set of options is returned.
*
* @return array
* Dropdown options
*/
function _mymodule($entity_type, $bundle) {
// Get fields for the selected node type.
$fields = field_info_instances($entity_type, $bundle);
$return = array();
foreach ($fields as $field) {
$return[$field['field_name']] = $field['label'];
}
if (count($return) == 0) {
$return['none'] = t('No fields for content type');
}
return $return;
}
/**
* Helper function to populate the node_type dropdown.
*
* @param string $key
* This will determine which set of options is returned.
*
* @return array
* Dropdown options
*/
function _mymodule_get_bundles($key = '') {
$return = array();
if($key == 'commerce_product') {
$return['product'] = t('Product');
}
else {
$entities = entity_get_info();
$bundles = $entities[$key]['bundles'];
foreach ($bundles as $bundle_key => $bundle) {
$return[$bundle_key] = $bundle['label'];
}
}
return $return;
}
So what I want is to update both the bundle
and fields
fields when the entity_type
field is changed. As it is now, the bundles
field is updated when entity_type
is changed, and fields
is changed correctly when bundles
is changed, but I can't get fields
to update when entity_types
is changed. When the code gets to where the fields
field is built in the form builder function, the #options
value has the correct values, but the page isn't updated with them. To try to accomplish that, I tried this code based on this answer:
function mymodule_dependent_dropdown_callback($form, $form_state) {
// The returned field depends on the triggering form field.
switch ($form_state['triggering_element']['#name']) {
case 'bundle':
return $form['fields'];
break;
case 'entity_type':
return array(
'#type' => 'ajax',
'#commands' => array(
ajax_command_replace("#bundles-replace", render($form['bundles'])),
ajax_command_replace("#fields-replace", render($form['fields']))
)
);
break;
}
}
but the end result is that the fields
field completely disappears from the page, even though $form['fields']
exists at that point in mymodule_dependent_dropdown_callback()
.
Based on this answer, I also tried replacing the entire form, like so:
function mymodule_form($node, &$form_state) {
$form = array();
$form['#prefix'] = '<div id="content-export-form">';
$form['#suffix'] = '</div>';
$form['entity_type'] = array(
'#type' => 'select',
'#title' => t('Entity Type'),
'#description' => t('Select the desired entity type'),
'#options' => $entity_options,
'#default_value' => $selected_entity_type,
'#ajax' => array(
'callback' => 'mymodule_dependent_dropdown_callback',
'wrapper' => 'content-export-formt'
),
);
...
}
function mymodule_dependent_dropdown_callback($form, $form_state) {
return $form;
}
but that didn't replace either 'bundleor 'fields
when entity_type
was updated.
What do I have to change to get the bundles
and fields
fields to be updated on the page when entity_type
is changed?
Thanks.
UPDATE . After looking through my code again, I realized I had a typo in the wrapper definition on the entity
field:
'wrapper' => 'content-export-formt'
Once I fixed that, it worked, sort of. When I first change the entity_type
field to Node
, it changes the bundle
field values appropriately and sets the options for the fields
field appropriately. However, when I select a different value in fields
, instead of replacing the form fields, it adds a new instance of the entity_type
and bundle
fields on the page, and this repeats for each time I select a new value from the bundle
field.