I have 2 dropdown select lists. The first a kanban process and the second a kanban step. When i select a kanban process the second dropdown should change based on the kanban process. But when i do i get an error: "An illegal choice has been detected. Please contact the site administrator."


function kanban_form_kanban_task_node_form_alter(&$form, &$form_state, $form_id) {
   
    $options_step = $form['field_kanban_step_ref']['und']['#options'];
    if($form)
    $form['field_kanban_process']['und']['#ajax'] = array(
            'event' => 'change',
            'callback' => 'ajax_dependent_dropdown_callback',
            'wrapper' => 'dropdown-second-replace',
            'method' => 'replace',
    );
    
    $form['field_kanban_step_ref']['und']['#prefix'] = '<div id ="dropdown-second-replace">';
    $form['field_kanban_step_ref']['und']['#suffix'] = '</div>';
    $form['field_kanban_step_ref']['und']['#options'] = $options_step;
    
}

function ajax_dependent_dropdown_callback($form, $form_state) {
    $process = $form['field_kanban_process']['und']['#value'];

    $form['field_kanban_step_ref']['und']['#options'] = get_step_reference($process);
    
    return $form['field_kanban_step_ref'];
    
}

function get_step_reference($kanban) {

$result = db_query('Select n.entity_id FROM {field_data_field_kanban_process_ref} n WHERE n.field_kanban_process_ref_target_id = :field_kanban_process_ref_target_id', array(':field_kanban_process_ref_target_id' => $kanban));
    foreach($result as $record) {
    
         $entity_id[] = $record->entity_id;
    }

    foreach($entity_id as $id) {
        $result2 = db_query('Select t.title FROM {node} t WHERE t.nid = :nid', array(':nid' => $id));

            foreach($result2 as $record2) {
        
                $title[] = $record2->title;
            }
    }
    
    return $title;
}

Comments

Jaypan’s picture

function ajax_dependent_dropdown_callback($form, $form_state) {
    $process = $form['field_kanban_process']['und']['#value'];

    $form['field_kanban_step_ref']['und']['#options'] = get_step_reference($process);
   
    return $form['field_kanban_step_ref'];
}

Two problems:

1) You are changing the $form element in your ajax callback above. This is causing the error you are seeing. Th only thing you should be doing in this function is returning the part of the form that should be inserted into the existing form. So everything in the above function that isn't part of the return statement should be part of your form definition.

2) You need to render the content that you return, using render().

bostuh’s picture

Could you demonstrate how i could do that?

Jaypan’s picture

If you download the examples module, there is an ajax example in there. That will show you how to do it.

bostuh’s picture

It should be mentioned that this dependent dropdown is going to be used in the function hook_form_alter()

bostuh’s picture

I have looked at the example. But i'm totally frustrated now. Could you please show me how do it?

Jaypan’s picture

It's fine that it's in hook_form_alter(). That doesn't make a difference.

Here's an example:


function my_form($form, &$form_state)
{
  $form['location'] = array
  (
    '#prefix' => '<div id="location_wrapper">',
    '#suffix' => '</div>',
  );
  $form['location']['country'] = array
  (
    '#type' => 'select',
    '#title' => t('Country'),
    '#options' => array
    (
      '' => '---',
      'canada' => t('Canada'),
      'japan' => t('Japan'),
    ),
    '#ajax' => array
    (
      // Wrapper set in $form['location']
      'wrapper' => 'location_wrapper',
      // Callback function to be shown later
      'callback' => 'my_ajax_callback',
    );
  );
  // The next part will only be entered if a country is selected,
  // ie - during the AJAX callback
  if(isset($form_state['values']['country']) && in_array($form_state['values']['country'], array('canada', 'japan')))
  {
    if($form_state['values']['country'] === 'canada')
    {
      $cities= array
      (
        '' => '---',
        1 => t('Vancouver'),
        2 => t('Montreal'),
      );
    }
    else
    {
     $cities= array
      (
        '' => '---',
        1 => t('Tokyo'),
        2 => t('Yokohama'),
      );
    }
    $form['location']['city'] = array
    (
      '#type' => 'select',
      '#title ' => t('City'),
      '#options' => $cities,
    );
  }
}

// Ajax callback
function my_ajax_callback($form, &$form_state)
{
  return render($form['location']);
}

As you can see, any alterations to the form are done in the form definition, as explained in the comments. In the ajax callback, I have only returned the section to be rendered, and I rendered it using render().

bostuh’s picture

Now it works fine. It populates the right things. But the selected is not saved inside the field_kanban_step_ref. How can i do this?

function kanban_form_kanban_task_node_form_alter(&$form, &$form_state, $form_id) {
    //$form['field_kanban_process']['#tree'] = true;
    $form['field_kanban_process']['und']['#ajax'] = array(
            'event' => 'change',
            'callback' => 'ajax_dependent_dropdown_callback',
            'wrapper' => 'dropdown-second-replace',
            'method' => 'replace',
    );

    $form['field_kanban_step_ref']['und']['#prefix'] = '<div id ="dropdown-second-replace">';
    $form['field_kanban_step_ref']['und']['#suffix'] = '</div>';
    

    if(isset($form_state['values']['field_kanban_process'])) {
    $process = $form_state['values']['field_kanban_process']['und'][0]['target_id'];

        if(strstr($process, '14')) {
            $options_step =  get_step_reference(14);    
        }
        else if(strstr($process, '39')){
           $options_step = get_step_reference(39);   
        }
        else {
            $options_step = array(
                '' => '- None -',
            );
        }
    $form['field_kanban_step_ref']['und']['#options'] = $options_step;
    }
    
}
function ajax_dependent_dropdown_callback($form, &$form_state) {
    return render($form['field_kanban_step_ref']);  
}
function get_step_reference($kanban) {

    $result = db_query('Select n.entity_id FROM {field_data_field_kanban_process_ref} n WHERE n.field_kanban_process_ref_target_id = :field_kanban_process_ref_target_id', array(':field_kanban_process_ref_target_id' => $kanban));
    foreach($result as $record) {
    
         $entity_id[] = $record->entity_id;
    }
    $title = array();
    $title[''] = '- None -';
    foreach($entity_id as $id) {
        $result2 = db_query('Select t.title FROM {node} t WHERE t.nid = :nid', array(':nid' => $id));

            foreach($result2 as $record2) {
                
                $title[$record2->title] = $record2->title;
            }
    } 
    return $title;
}
Jaypan’s picture

It looks like you have set up your ajax properly, which will let the user select a value from the options you give. The next thing you need to do is to attach a submit function to be called after the form is submitted. You can add your submit function to the $form element's #submit array, and it will be called after any existing submit callbacks:


function my_module_form_alter(&$form, &$form_state, $form_id)
{
  // Rest of form not shown
  if($form_id === 'my_form_id')
  {
     $form['#submit'][] = 'my_submit_function';
  }
}

function my_submit_function($form, &$form_state)
{
  // The value submitted to your #ajax form element
  // is part of the $form_state['values'] array. You can
  // take care of saving it to the database or whatever, here.
}

salah2020’s picture

before submit everything works fine and my second dropdownlist failed with right values but..
after submit i still see this error massage "An illegal choice has been detected. Please contact the site administrator." and my second dropdownlist going to be empty again. could anyone help..!

Shashwat Purav’s picture

Always paste the code for reference. Always.

Thank You,
Shashwat Purav

nitin.k’s picture


$form['field_kanban_process']['und']['#validated'] = TRUE;

Sajjad Zaheer’s picture

Ajax Chain Select Module addresses problems specified. you can use it for free from:
https://www.drupal.org/project/ajax_chain_select

nixar’s picture

Does your module work with Webform? Thanks