-1

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?

2
  • 1
    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: jaypan.com/tutorial/…
    – Jaypan
    Jul 24 at 8:25
  • 1
    There is a typo in the first callback: $form['outpout']['#options'] = $city_options;. It should be output, not outpout.
    – apaderno
    Jul 24 at 8:26
2

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);

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.