问题
I wrote this code for dynamic dropdown select list in hook_form_alter. Options are populated by an external DB.
function car2db_annuncio_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if ($form_id == 'node_annuncio_form') {
$options_type = car2db_annuncio_type_dropdown_options();
$form['field_marca']['#prefix'] = '<div id="field_marca">';
$form['field_marca']['#suffix'] = '</div>';
$form['field_tipologia']['widget']['#options'] = $options_type;
$form['field_tipologia']['widget']['#ajax'] = array(
'event' => 'change',
'callback' => 'car2db_annuncio_make_ajax_callback',
'wrapper' => 'field_marca',
'disable-refocus' => FALSE,
'progress' => [
'type' => 'throbber',
'message' => t('Verify...'),
]
);
}
}
function car2db_annuncio_type_dropdown_options() {
$connection = Database::getConnection('default', 'migrate');
$dropdown_type = ['none' => '- Seleziona - '];
$sql_type = "SELECT * FROM `car_type`";
$query_type = $connection->query($sql_type);
$res_type = $query_type->fetchAll();
foreach ($res_type as $row){
$key = $row->id_car_type;
$value = $row->name;
$dropdown_type[$key] = $value;
}
return $dropdown_type;
}
function car2db_annuncio_make_dropdown_options($key_type) {
$connection = Database::getConnection('default', 'migrate');
$dropdown_make = ['none' => '- Seleziona - '];
$sql_make = "SELECT * FROM `car_make` WHERE `id_car_type` = :tipo";
$query_make = $connection->query($sql_make, [':tipo' => $key_type]);
$res_make = $query_make->fetchAll();
foreach ($res_make as $row){
$Key_make = $row->id_car_make;
$Make_value = $row->name;
$dropdown_make[$Key_make] = $Make_value;
}
return $dropdown_make;
}
function car2db_annuncio_make_ajax_callback(array &$form, FormStateInterface $form_state) {
if ($selectedValue = $form_state->getValue('field_tipologia')) {
$selectedValue = (int) $selectedValue[0]['value'] ? (int) $selectedValue[0]['value'] : 0;
$options_marca = car2db_annuncio_make_dropdown_options($selectedValue);
$form['field_marca']['widget']['#options'] = $options_marca;
}
return $form['field_marca'];
}
Now, when click on "Save button", there is always "An illegal choice is detected...." error. I also tried loading options into the hook_form alter, but it always returns an error. Where am i wrong?
回答1:
I remember this confusing the hell out of me back in the day when I first started playing with ajax forms in Drupal.
Hopefully I am remembering this correctly.
Basically, you have to move your logic for adding the dynamic options into the form build function (but in your case, it's the alter function).
When the ajax function is called, the form is still rebuilt and your alter function is called (and has the current form_state).
Your ajax function will just return the new form element.
Something like below (untested)
function car2db_annuncio_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if ($form_id == 'node_annuncio_form') {
$options_type = car2db_annuncio_type_dropdown_options();
$form['field_marca']['#prefix'] = '<div id="field_marca">';
$form['field_marca']['#suffix'] = '</div>';
$form['field_tipologia']['widget']['#options'] = $options_type;
$form['field_tipologia']['widget']['#ajax'] = array(
'event' => 'change',
'callback' => 'car2db_annuncio_make_ajax_callback',
'wrapper' => 'field_marca',
'disable-refocus' => FALSE,
'progress' => [
'type' => 'throbber',
'message' => t('Verify...'),
]
);
// Check selected value here.
if ($selectedValue = $form_state->getValue('field_tipologia')) {
$selectedValue = (int) $selectedValue[0]['value'] ? (int) $selectedValue[0]['value'] : 0;
$options_marca = car2db_annuncio_make_dropdown_options($selectedValue);
$form['field_marca']['widget']['#options'] = $options_marca;
}
}
}
function car2db_annuncio_type_dropdown_options() {
$connection = Database::getConnection('default', 'migrate');
$dropdown_type = ['none' => '- Seleziona - '];
$sql_type = "SELECT * FROM `car_type`";
$query_type = $connection->query($sql_type);
$res_type = $query_type->fetchAll();
foreach ($res_type as $row){
$key = $row->id_car_type;
$value = $row->name;
$dropdown_type[$key] = $value;
}
return $dropdown_type;
}
function car2db_annuncio_make_dropdown_options($key_type) {
$connection = Database::getConnection('default', 'migrate');
$dropdown_make = ['none' => '- Seleziona - '];
$sql_make = "SELECT * FROM `car_make` WHERE `id_car_type` = :tipo";
$query_make = $connection->query($sql_make, [':tipo' => $key_type]);
$res_make = $query_make->fetchAll();
foreach ($res_make as $row){
$Key_make = $row->id_car_make;
$Make_value = $row->name;
$dropdown_make[$Key_make] = $Make_value;
}
return $dropdown_make;
}
function car2db_annuncio_make_ajax_callback(array &$form, FormStateInterface $form_state) {
// Just return the form element (that has been rebuilt in the form_alter)
return $form['field_marca'];
}
来源:https://stackoverflow.com/questions/60662918/an-illegal-choice-is-detected-error-with-dynamic-dropdown-select-list-i-dru