2

I have created a content type (Geological Locations) with 2 fields, Country and States.

The Country field is a select box, and States field is a multiselect. So if i select a Country, the States multiselect should be populated based on the selected Country using AJAX.

In my custom module, i used node_form_alter() to customize the node creation form.

I have tried the below code, but it is not working as expected.

function demo_form_geological_locations_node_form_alter(&$form, &$form_state, $form_id) {
    $form['additional_settings']['#access'] = false;
    $form['field_country']['und']['#options'] = array(''=>'Select', 'india'=>'India', 'usa'=>'USA');
    $selected = isset($form_state['values']['field_country']) ? $form_state['values']['field_country'] : '';

    $form['field_country']['und']['#ajax'] = array(
          'callback' => 'ajax_states_callback',
          'wrapper' => 'states-wrapper',
    );

    $form['field_states']['#prefix'] = '<div id="states-wrapper">';
    $form['field_states']['#suffix'] = '</div>';
    $form['field_states']['und']['#options'] = ajax_get_state_options($selected);

    return $form;
}

function ajax_states_callback($form, $form_state) {
    return $form['field_states'];
}

function ajax_get_state_options($key = '') {
    $options = array(
        t('usa') => drupal_map_assoc(
          array(
            t('Florida'),
            t('Georgia'),
            t('Atlanta')
          )
        ),
        t('india') => drupal_map_assoc(
          array(
            t('Maharashtra'),
            t('Gujarat'),
            t('Karnataka')
          )
        )
    );

    if (isset($options[$key])) {
        return $options[$key];
    }
    else {
        return array();
    }
}

Can anyone tell me where i am going wrong? I am expecting the output like below screenshot, when i select the Country "India":

enter image description here

4
  • Have you considered an alternative method: Create your geo information as parent/child terms in a vocabulary, then use hierarchical select module in multi select mode. – Quentin Campbell Nov 10 '14 at 8:49
  • Actually the data of Countries and States comes from an external API (hundreds of records) and i parse it to create custom arrays, so that i can use AJAX to populate States field, based on the selected Country. – shasi kanth Nov 10 '14 at 10:15
  • Not sure if my code is not working, because i am using form_alter(). – shasi kanth Nov 12 '14 at 6:03
  • As an update, the solution by Naveen Valecha worked out well. And I have shifted to the Dev version of the multiselect module, as the original version is giving some warnings with AJAX onchange. – shasi kanth Nov 18 '14 at 4:52
1
+50

Awesome question with full detail.After checking I tested it on my local dev box for its fix. Use the below code for its fix. I have written the problem & its fix below.

    <?php

function demo_form_geological_locations_node_form_alter(&$form, &$form_state, $form_id) {

  $form['additional_settings']['#access'] = false;
  $form['field_country']['und']['#options'] = array(''=>'Select', 'india'=>'India', 'usa'=>'USA');
  $selected = isset($form_state['values']['field_country']) ? $form_state['values']['field_country']['und'][0]['value'] : '';
  $form['field_country']['und']['#ajax'] = array(
    'callback' => 'ajax_states_callback',
    'wrapper' => 'states-wrapper',
  );
  $form['field_states']['#prefix'] = '<div id="states-wrapper">';
  $form['field_states']['#suffix'] = '</div>';
  $form['field_states']['und']['#options'] = ajax_get_state_options($selected);
  return $form;
}

function ajax_states_callback($form, $form_state) {
  return $form['field_states'];
}

function ajax_get_state_options($key = '') {
    $options = array(
        t('usa') => drupal_map_assoc(
          array(
            t('Florida'),
            t('Georgia'),
            t('Atlanta')
          )
        ),
        t('india') => drupal_map_assoc(
          array(
            t('Maharashtra'),
            t('Gujarat'),
            t('Karnataka')
          )
        )
    );

    if (isset($options[$key])) {
        return $options[$key];
    }
    else {
        return array();
    }
}

?>

Problem was at line

$selected = isset($form_state['values']['field_country']) ? $form_state['values']['field_country'] : '';

you were passing the array to the selected value .i.e. countries array but the function ajax_get_state_options needs the key of selected country to return the array of states based on selected country.

I have tested this on php 5.3.27 Other suggestions :

  1. you can also use the existing field api wrapper generated by field api.

P.S. : Double slap myself to track this small mistake in 1h 30 minutes.

1

Have you tried one of the following modules?

Multiselect (this one suits the most)

Hierarchical Select (relatively easy to configure)

Conditional Fields (requires separate dropdown lists)

A combination of Multiselect and Hierarchical Select will mostly help you achieve what you have shown.

Regards,

Supriya Rajgopal

3
  • Can i use Hierarchical Select module with Form API to populate the Countries and States, using AJAX? – shasi kanth Nov 11 '14 at 10:34
  • Yes shasi, I think you can use. Please read the README.txt in the module for more information. – Supriya Rajgopal Nov 12 '14 at 6:04
  • Hierarchical select is broken in D7, maybe try Simple Hierarchical Select instead. – Darvanen Nov 12 '14 at 12:53
0

You return $form['field_states'] wrapped in <div id="states-wrapper"> to replace content of <div id="states-wrapper">. Try removing wrapper when returning form element via AJAX like:

function ajax_states_callback($form, $form_state) {
    unset($form['field_states']['#prefix']);
    unset($form['field_states']['#suffix']);
    return $form['field_states'];
}

You should consider moving $form['field_states'] to a container.

2
  • I tried removing wrapper while returning AJAX response, but it did not work. Can you clarify how to use a container for the field? – shasi kanth Nov 11 '14 at 7:35
  • I meant, something like $form['field_states_container'] = array('#type' => 'container', '#prefix' => '<div id="states-wrapper">', '#suffix' => '</div>', 'field_states' => $form['field_states']); unset($form['field_states']);, however I'm not sure it won't break anything in further form processing, since it's not a custom field. Anyway you can try it to check whether it is the reason. – Alex Bukach Nov 11 '14 at 13:01
0

Try Reference Field Option Limit
Find the Documentation related to this module here Documentation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.