What are the steps required to reproduce the bug?

  1. Create a form in code.
  2. Add a select field with multiple selection enabled.
  3. Add a file upload field.
  4. Attach an AJAX callback to the select field that just returns the same form.
  5. Choose more than 1 option in the select field. The system will show the following validation error: An illegal choice has been detected. Please contact the site administrator..

Here's a sample custom module that demonstrates the issue:

File: sample.info:

name = Sample module
description = Sample module for testing the validation callback of AJAX enabled select fields.
package = Custom
core = 7.x
version = 1.0

File: sample.module:

function sample_menu() {
  $items['sample'] = array(
    'title' => 'Sample form page',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('sample_page_form'),
    'access callback' => TRUE,
  );

  return $items;
}

function sample_page_form($form, &$form_state) {
  $form['#id'] = 'sample-page-form';

  $form['list'] = array(
    // This does not work.
    '#type' => 'select',
    // However if the type is changed to "checkboxes", validation works properly.
    // '#type' => 'checkboxes',
    '#title' => t('Select something'),
    '#options' => array(
      'option1' => t('Option 1'),
      'option2' => t('Option 2'),
      'option3' => t('Option 3'),
    ),
    '#multiple' => TRUE,
    '#ajax' => array(
      'method' => 'replaceWith',
      'wrapper' => $form['#id'],
      'callback' => 'sample_page_form_ajax',
    ),
  );
  $form['file_upload'] = array(
    '#type' => 'file',
    '#title' => t('Sample upload field'),
  );

  $form['actions'] = array('#type' => 'actions');
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit the form',
  );

  return $form;
}

function sample_page_form_ajax($form, $form_state) {
  return $form;
}

What behavior were you expecting?

To be able to select multiple options in the select field with AJAX callback, without validation errors.

This works properly when using `checkboxes` instead of `select` form element.

What happened instead?

The system showed validation errors instead.

My investigation

I narrowed the problem down to the following: when a file upload field is added to a form, values submitted from a select field with multiple options enabled will be passed as comma separated values instead of arrays. This triggers the validation errors because the system cannot match the submitted value with the values defined in the #options property of the field.

Here's what I mean:

  1. Values passed without the file upload field:

    Array
    (
      [list] => Array
        (
          [option1] => option1
          [option2] => option2
        )
    )
    
  2. Values passed with the file upload field:

    Array
    (
      [list] => Array
        (
          [option1,option2] => option1,option2
        )
    )
    

Let me know if you need any additional information.

Thanks!

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

aramboyajyan created an issue. See original summary.

aramboyajyan’s picture

Issue summary: View changes
aditya.n’s picture

I found a work around which converts

Array
(
  [list] => Array
    (
      [option1,option2] => option1,option2
    )
)

into :

Array
(
  [list] => Array
    (
      [option1] => option1
      [option2] => option2
    )
)

But still the error shows up, this is what I have done:

In the ajax callback function:-

   function sample_page_form_ajax($form, $form_state) {
	if( isset($form_state['values']['list'])){
		$items = $form_state['values']['list'];
		if (!empty($items) && is_array($items)) {
			$first = reset($items);
			if ($first && strpos($first, ',') !== FALSE) {
				$selected_items = explode(',', $first);
				$items = array();
				foreach ($selected_items as $selected_item) {
          $items[$selected_item] = $selected_item;
        }
        $form_state['values']['list'] = $items;
			}
		}
	}
  return $form;
}
aditya.n’s picture

Status: Active » Needs work
esha’s picture

Same here, only in a slightly more complex setup...

Thanks for breaking it down!

Any news?

Ujwala_D’s picture

Status: Needs work » Needs review

Hi aramboyajyan,

#3 is working but needs to add code of one line before returning form. Please check it below:


function sample_page_form_ajax($form, $form_state) {
  if( isset($form_state['values']['list'])){
    $items = $form_state['values']['list'];
    if (!empty($items) && is_array($items)) {
      $first = reset($items);
      if ($first && strpos($first, ',') !== FALSE) {
        $selected_items = explode(',', $first);
        $items = array();
        foreach ($selected_items as $selected_item) {
         $items[$selected_item] = $selected_item;
        }
        $form_state['values']['list'] = $items;
      }
    }
  }
 $elements = array($form['list'], $form['file_upload']);
    return $elements;
}

You will not get the error like 'An illegal choice has been detected. Please contact the site administrator..'

aditya.n’s picture

Status: Needs review » Needs work
FileSize
50.69 KB

@ujwal_D the code returning the element array does not give error 'An illegal choice has been detected. Please contact the site administrator..' but it isn't the right way, also when you select more that one values from the select list and then if you refresh the page and then try to select other multiple values, drupal throws error without any error message being displayed, which isn't friendly. I am attaching the related screen shot.

tsmulugeta’s picture

This is the exact problem I've been having. Any update on the solution?

tsmulugeta’s picture

Perhaps this might help although I couldn't completely understand it: https://www.drupal.org/node/2229055