10

I have four entity reference fields to user entity in a form. Host form is node edit form. Three of them are select lists, last is Inline Entity Form.

After adding a user entity via IEF I'm trying to update select lists values:

function ebep_users_feature_users_list_ajax($form, $form_state) {

  $ief = array_shift($form_state['inline_entity_form']);
  $options = array('_node' => t('- None -'));
  $commands = array();

  foreach($ief['entities'] as $data) {
    $options[$data['entity']->uid] = $data['entity']->name;
  }

  foreach(_ebep_users_feature_getUserListFieldNames() as $fieldName) {
    $form[$fieldName]['und']['#options'] = $options;
    $commands[] = ajax_command_replace('#'.$fieldName.'_wrapper', drupal_render($form[$fieldName]));
  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

It works, but when I try to add another user via IEF I am getting:

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

15

Just set

$bla['#validated'] = TRUE

On the select that will be updated with AJAX.

Checkout "Illegal Choice has been detected"

  • 1
    If I remember well I tried this, without a success in my case, thanks – Codium Jan 14 '14 at 10:49
  • 1
    I'm afraid this doesn't work for me either. – kevin.coyle Apr 17 '15 at 10:29
  • Does this not make the form less secure? – Binny Jan 15 at 7:27
3

I have faced this problem number of times in Drupal 6, changing the values of Select list via Ajax.

Here is what you can do is

  1. If possible, try to insert all the possible values in the in the Field API, you need to edit that field, and then when you change the values, you will have to make sure that only the listed values are in the list.
  2. Solution that I implemented was, you can change the field type from Select list to textfield, from Field API, and ask Drupal to save the value as is. Now, on form runtime, you will have to alter the form, change the type to select list, and push in options, which you want to. While submission as well, you will have to assign the correct value required by the field, that will be saved in DB as is. Make sure your submit handler is called before the default form submit handler, for that you may use array_merge

If first solution works for you, you will save a lot of time coding and testing things. BUT if the list in the drop down is dynamic and you have no control over it, you might have to go with second solution.

Do post if you face any issues, I have done quite lot of work on this problem, for my project, and I did for ~50 forms, PHEW !!! :)

3

I have found the best way round this is to set the #value on the select list.

If we have the value in formstate and it is in our options then we will not get an error. If our value is not in the options then select the first option in our options and use that.

$form['example'] = array(
    '#type' => 'select',
    '#title' => t('Example'),
    '#options' => $options,
    '#value' => isset($form_state['values']['example']) && in_array($form_state['values']['example'],$options)?$form_state['values']['example']:key($options),
  );
2

My solution:

/**
 * Implements hook_form_FORM_ID_alter()
 */
function ebep_users_feature_form_ebep_exhibitor_profile_node_form_alter(&$form, &$form_state, $form_id) {

  foreach(_ebep_users_feature_getUserListFieldNames() as $fieldName) {
    $form[$fieldName]['und']['#prefix'] = '<div id="'.$fieldName . '_wrapper">';
    $form[$fieldName]['und']['#suffix'] = '</div>';
    $form[$fieldName]['und']['#options'] = _ebep_users_feature_getOptionsValuesFromIEFList($form_state);
  }

  $form['#attached']['css'] = array(
    drupal_get_path('module', 'ebep_users_feature') . '/assets/styles.css',
  );

  $form['#attached']['js'] = array(
    drupal_get_path('module', 'ebep_users_feature') . '/assets/scripts.js',
  );

  $form['users_refresh'] = array(
    '#type' => 'submit',
    '#value' => t('Refresh users list'),
    '#ajax' => array(
      'callback' => 'ebep_users_feature_users_list_ajax',
    ),
  );
}

function ebep_users_feature_users_list_ajax($form, $form_state) {

  $commands = array();

  foreach(_ebep_users_feature_getUserListFieldNames() as $fieldName) {
    $form[$fieldName]['und']['#options'] = _ebep_users_feature_getOptionsValuesFromIEFList($form_state);
    $commands[] = ajax_command_replace('#'.$fieldName.'_wrapper', drupal_render($form[$fieldName]));
  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

function _ebep_users_feature_getOptionsValuesFromIEFList($form_state) {
  static $options = array();

  if (empty($options)) {
    $ief = array_shift($form_state['inline_entity_form']);
    $options['_node'] = t('- None -');

    foreach($ief['entities'] as $data) {
      $options[$data['entity']->uid] = $data['entity']->name;
    }
  }

  return $options;
}
-1

In your ajax callback, add:

...

drupal_get_messages();
form_get_errors();

return array('#type' => 'ajax', '#commands' => $commands);

As a security precaution, the core _form_validate() function checks if an element's #options key has changed from what what was set in the original build (which they have). By calling drupal_get_messages() and form_get_errors() we basically tell Drupal to ignore any errors/messages while running our ajax request. :)

  • Error message is gone but the select element still contains the error class.How to remove or prevent that? – Tejas Vaidya May 25 '16 at 13:30
  • This is the Drupal equivalent of putting tape over a warning light on your vehicle's dash board. – Frank Robert Anderson Jan 12 '18 at 20:56

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.