7

I have written code like below and all works fine, but while submitting the form I get the error below. I am trying to filter the second dropdown based on the first drop down selection.

An illegal choice has been detected. Please contact the site administrator.

How do I overcome that error?

function dynamic_location_dropdown_form_alter(&$form, $form_state, $form_id) {
  if($form_id == 'product_node_form') {

  $location_options = array();

  if(isset($form['field_destination']['und']['#default_value'][0])) {
    $destination = $form['field_destination']['und']['#default_value'][0];
  }
  else {
    $destination = 0;
  }

  $location_options = dynamic_location_dropdown_locations($destination);

  $form['field_destination']['und']['#ajax'] = array(
    'event' => 'change',
    'wrapper' => 'squadron-wrapper',
    'callback' => 'dynamic_location_dropdown_ajax_callback',
    'method' => 'replace',
  );
  $form['field_product_location']['#validated'] = true;
  $form['field_product_location']['und']['#prefix'] = '<div id="squadron-wrapper">';
  $form['field_product_location']['und']['#suffix'] = '</div>';
  $form['field_product_location']['und']['#options'] = $location_options;
  }
}

function dynamic_location_dropdown_ajax_callback($form, $form_state) {
  $country_id = $form['field_destination']['und']['#value'];
  $form['field_product_location']['#validated'] = true;
  $form['field_product_location']['und']['#options'] =  dynamic_location_dropdown_locations($country_id);

  return $form['field_product_location'];
}

function dynamic_location_dropdown_locations($destination_id) {
  $nodes = array();
  $nodes[''] = '- None -';
  if($destination_id != '') {
    $select = db_query("
      SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created
      FROM {node} node
      LEFT JOIN {field_data_field_location_country} field_data_field_location_country 
      ON node.nid = field_data_field_location_country.entity_id 
      AND (field_data_field_location_country.entity_type = 'node' 
      AND field_data_field_location_country.deleted = '0')
      WHERE (( (node.status = '1') 
      AND (node.type IN  ('location')) 
      AND (field_data_field_location_country.field_location_country_nid = $destination_id)))
      ORDER BY node_title ASC
    ");
    $nodes[''] = '- None -';
    foreach ($select as $node) {
      $nodes[$node->nid] = $node->node_title;
    }
  }

  return $nodes;
}
1
  • well, you're already using '#validated' => TRUE which should take care of that. So my guess is that in some properties you have the 'und' key and not in the form array where you use the '#validated' key ...?
    – 30equals
    May 17, 2012 at 21:04

3 Answers 3

8

The problem is most likely because of a requirement for FAPI AJAX which is documented in AJAX Forms in Drupal 7, though can be easily missed.

Changes to the form must only be made in the form builder function (ajax_example_autocheckboxes() in the example here), or validation will fail. The callback function must not alter the form or any other state.

The fact that you're setting the form element [#options] in the AJAX callback is definitely a problem. The AJAX callback should only return the array or HTML to be printed, not change the form. That callback should only contain the return statement.

The changes to your form should be made in the form_alter. Also, you should use the form_state array to check whether a value has been selected for your first dropdown. This will be updated during an AJAX request.

I recommend looking at the examples module, as well as these pages for more information on AJAX in FAPI. It can definitely be tricky.

1
3

The below method can be used to neglect errors only for those fields into which value has been added through ajax
As per the code given below you can enter the field element which gives error so that the value changed in the second dropdown due to change in the first dropdown due to the use of ajax will not show an error.

/**
 * Custom Form Validation.
 * Removes all form validation errors caused by a 'foo][bar' form element.
 */
function my_module_form_validate($form, &$form_state) {
  $errors = form_get_errors();
  if ($errors) {
    // Clear errors.
    form_clear_error();
    // Clear error messages.
    $error_messages = drupal_get_messages('error');
    // Initialize an array where removed error messages are stored.
    $removed_messages = array();


// Remove all errors originated by the 'foo][bar' element.
    foreach ($errors as $name => $error_message) {
      if ($name == 'foo][bar') {
        $removed_messages[] = $error_message;
        unset($errors[$name]);
      }
    }


// Reinstate remaining errors.
    foreach ($errors as $name => $error) {
      form_set_error($name, $error);
      // form_set_error() calls drupal_set_message(), so we have to filter out
      // these from the error messages as well.
      $removed_messages[] = $error;
    }


// Reinstate remaining error messages (which, at this point, are messages that
    // were originated outside of the validation process).
    foreach (array_diff($error_messages['error'], $removed_messages) as $message) {
      drupal_set_message($message, 'error');      
    }
  }
}
1

This seems to be a core bug https://www.drupal.org/node/153774 and solutions mentioned here actually cause more problems.

When #ajax is used for a select element, if more than one options is selected "illegal choice error" will be generated. But why? After a bit of investigation it turned out that when #ajax is enabled it causes the select element to submit values like array(200,250) instead of array(200 => 200, 250 => 250) So it causes problem with options validation code inside _form_validate function and it no longer can check selected options against available options, here is the code : This happens only when more than one option is selected and #ajax is used. The fix is to correct the submitted value before validation

I've written a module to automatically workaround this bug, it may not work in all cases but it's a clear workaround you can use it as a starting point.

https://www.drupal.org/sandbox/sinasalek/2312751

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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