I have a form with 3 dropdowns. When changing the first one, it updates the 2 other by an ajax call. Once the 2 selects are re-rendered, when the user submits the form, it no longer pass in the submitForm()
method. I have tried many combinations to try to fix this but found no way. Here is the last state of my attempts.
In a module for geo location, I load a form in a block:
in src/Plugin/Block/GeoPopupBlock.php:
class GeoPopUpBlock extends BlockBase {
public function build() {
if(!$cookie = Util::getCookie()){
$message = 'Cookie was not set.';
\Drupal::logger($message);
die($message);
}
$buildForm = \Drupal::formBuilder()->getForm('\Drupal\my_module\Form\GeoForm');
// $buildForm = \Drupal::formBuilder()->getForm(new GeoForm());
$build['#form'] = $buildForm;
[...]
return $build;
In src/Form/GeoForm.php
<?php
[...]
class GeoForm extends FormBase{
public function getFormId(){
return 'geo_form';
}
public function buildForm(array $form, FormStateInterface $form_state){
if (!$cookie = Util::getCookie()){
$message = 'Cookie was not set.';
\Drupal::logger(__CLASS__)->critical($message);
die($message);
}
$form['country'] = array(
'#type' => 'select',
'#options' => $this->getCountries(),
'#default_value' => $cookie['countryId'],
'#attributes' => array('class' => array('edit-country')),
'#ajax' => array(
'callback' => '::ajaxFillProvider',
'wrapper' => 'provider-language',
'method' => 'replaceWith',
'progress' => array(
'type' => 'throbber',
'message' => NULL,
),
),
);
$form['provider'] = array(
'#prefix' => '<div id="provider-language">',
'#type' => 'select',
'#options' => $this->getProviders($cookie['countryId']),
'#default_value' => $cookie['providerId'],
'#attributes' => array('class' => array('edit-provider')),
);
$form['language'] = array(
'#type' => 'select',
'#options' => $this->getLanguages($cookie['countryId']),
'#default_value' => $cookie['languageId'],
'#suffix' => '</div>',
'#attributes' => array('class' => array('edit-language')),
);
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = array(
'#prefix' => '<div class="flex"><div class="submit-button">',
'#type' => 'submit',
'#value' => $this->t('Access my content'),
'#suffix' => '</div>',
);
$form['actions']['decline'] = array(
'#prefix' => '<div class="decline-button" id="decline-button">',
'#markup' => t('Decline'),
'#suffix' => '</div></div>',
);
return $form;
}
public function ajaxFillProvider(array &$form, FormStateInterface $form_state){
$ajaxForm['provider'] = array(
'#prefix' => '<div id="provider-language">',
'#type' => 'select',
'#name' => 'provider', // have to add this otherwise the select would have no name!
'#options' => $this->getProviders($form_state->getValue('country')),
'#attributes' => array('class' => array('edit-provider')),
);
$ajaxForm['language'] = array(
'#type' => 'select',
'#name' => 'language', // have to add this otherwise the select would have no name!
'#options' => $this->getLanguages($form_state->getValue('country')),
'#suffix' => '</div>',
'#attributes' => array('class' => array('edit-language')),
);
return $ajaxForm;
}
/**
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
public function submitForm(array &$form, FormStateInterface $form_state){
if (!$cookie = Util::getCookie()){
$message = 'Cookie was not set.';
\Drupal::logger(__CLASS__)->critical($message);
die($message);
}
$commConfig = \Drupal::config('communication.settings');
$cookie['countryId'] = $form_state->getValue('country');
$cookie['providerId'] = $form_state->getValue('provider');
$cookie['languageId'] = $form_state->getValue('language');
Util::setCookie($cookie);
}
[... more private methods]
}
At this point the ajax is working and filling the 2 selects with new values. Submitting the form will send all values to the server. But for an unknown reason, it will not pass in the submitForm()
.
Note that if I remove the extra '#name' => 'provider',
and '#name' => 'language',
it will pass in the submitForm()
but since the new select tags have no name attribute, the form in unable the use those form elements.