Score:-1

Why do I get "An invalid selection has been identified." from the form my code creates?

ng flag

I am using the following code for a form.

public function buildForm(array $form, FormStateInterface $form_state) {
  $region_options = static::getFirstDropdownOptions();
  $form['vvv_region'] = [
    '#type' => 'select',
    '#title' => $this->t('region select field'),
    '#options' => $region_options,
    '#empty_option' => t('- Select region -'),
    '#ajax' => [
      'callback' => '::myAjaxCallback',
      'disable-refocus' => FALSE,
      'event' => 'change',
      'wrapper' => 'edit-output',
      'progress' => [
        'type' => 'throbber',
        'message' => $this->t('Verifying entry...'),
      ],
    ]
  ];
    
  $region_selected = $form_state->getValue('vvv_region');
  $city_options = static::getSecondDropdownOptions($region_selected);
    
  $form['output'] = [
    '#type' => 'select',
    '#title' => $this->t('city select field'),
    '#options' => $city_options,     
    '#prefix' => '<div id="edit-output">',
    '#suffix' => '</div>',
    '#empty_option' => t('- Select city -'),
    '#default_value' => '',
    '#ajax' => [
      'callback' => '::cityAjaxCallback',
      'disable-refocus' => FALSE,
      'event' => 'change',
      'wrapper' => 'edit-city',
      'progress' => [
        'type' => 'throbber',
        'message' => $this->t('Verifying entry...'),
      ],
    ]
  ];
    
  $city_select = $form_state->getValue('output');
  $suburb_options = static::getSuburbDropdownOptions($city_select);
        
  $form['sur'] = [
    '#type' => 'select',
    '#options' => $suburb_options,     
    '#prefix' => '<div id="edit-city">',
    '#suffix' => '</div>',
    '#empty_option' => t('- Select sururb -'),
    '#default_value' => array(''),
  ];
  return $form;
}

public function myAjaxCallback(array &$form, FormStateInterface $form_state) {
  $region_selected = $form_state->getValue('vvv_region');
  $city_options = static::getSecondDropdownOptions($region_selected);

  if ($form_state->getErrors()) {
    \Drupal::messenger()->addError($region_selected);
    $form_state->setRebuild();
  }
  
  $form['outpout']['#options'] = $city_options;
          
  return $form['output']; 
}
    
public function cityAjaxCallback(array &$form, FormStateInterface $form_state) {
  $city_select = $form_state->getValue('output');
  $sur_data = static::getSuburbDropdownOptions($city_select);

  if ($form_state->getErrors()) {
    \Drupal::messenger()->addError($city_select);
    $form_state->setRebuild();
  }

  $form['sur']['#options'] = $sur_data;

  return $form['sur']; 
}

When the form is submitted, I get the following error.

An invalid selection has been identified. Please contact the site administrator.

What's wrong with the code I am using?

Jaypan avatar
de flag
You can't change the value of the options in the ajax callback. It must be done in the form definition. You can read an example of how to do that in this tutorial I wrote: https://www.jaypan.com/tutorial/drupal-form-api-ajax-form-and-results-same-page
apaderno avatar
us flag
There is a typo in the first callback: `$form['outpout']['#options'] = $city_options;`. It should be *output*, not *outpout*.
Score:2
us flag

There are two errors in the code shown in the question.

It's only the form builder that can add options to form elements. Differently, you will get the error you quoted.

An invalid selection has been identified. Please contact the site administrator.

What the AJAX callback does is simply returning the form element that needs to be changed. In your case, the code is the following one.

public function myAjaxCallback(array &$form, FormStateInterface $form_state) {
  return $form['output']; 
}
    
public function cityAjaxCallback(array &$form, FormStateInterface $form_state) {
  return $form['sur']; 
}

AN AJAX callback for a form doesn't usually handle validation errors.

The second error is in the form builder, which uses the following code.

$region_selected = $form_state->getValue('vvv_region');

When the form is first built, $form_state->getValue('vvv_region') doesn't return any value, as the form isn't yet submitted, even via AJAX. It's only when the form is submitted via AJAX that $form_state->getValue('vvv_region') returns a value. That line needs to be changed as follows.

$region_selected = $form_state->hasValue('vvv_region') ? $form_state->getValue('vvv_region') : key($region_options);

Similarly, $city_select = $form_state->getValue('output'); needs to be changed.

$city_select = $form_state->hasValue('output') ? $form_state->getValue('output'): key($city_options);
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.