Добавьте событие #ajax в пользовательский составной элемент
Я создал пользовательский составной элемент для веб-формы (6.0), в котором есть поле даты и поле выбора. Идея заключается в том, что когда пользователь выбирает дату, выполняется вызов API, который возвращает доступные временные интервалы для бронирования.
Я знаком с тем, как это обычно делается в формах FormBase и проверяет form_state, чтобы сообщить значения сборки, но я застрял здесь.
class WebformTourAvailabilityComposite extends WebformCompositeBase {
/**
* {@inheritdoc}
*/
public static function getCompositeElements(array $element) {
$date_format_entity = DateFormat::load('html_date');
$date_format = $date_format_entity->getPattern();
$elements = [];
$elements['tour_date'] = [
'#type' => 'date',
'#title' => t("Tour Date"),
'#date_date_format' => $date_format,
'#date_year_range' => '0:15',
'#attributes' => [
'min' => '[webform_submission:created:html_date]',
'onkeydown' => 'return false'
],
#'#datepicker' => TRUE,
'#datepicker_button' => TRUE,
'#date_label_position' => 'invisible',
'#required' => TRUE,
'#ajax' => [
'callback' => 'mymodule_get_date_options',
'wrapper' => 'available-times'
]
];
$elements['tour_time'] = [
'#type' => 'select',
'#title' => t('Tour time'),
'#prefix' => '<div id="available-times">',
'#suffix' => '</div>',
#'#options' => [],
];
return $elements;
}
}
В моем модуле.модуль:
function mymodule_webform_submission_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
$selected = $form_state->getValues();
if (isset($selected["select_appointment"]["tour_date"])) {
$response = \Drupal::httpClient()->get('https://nestiolistings.com/api/v2/appointments/group/123/available-times');
$options = json_decode($response->getBody()->getContents(), TRUE);
#$form["elements"]["step_1"]["select_appointment"]["tour_time"]["#options"] = $options['data'];
$form["elements"]["step_1"]["select_appointment"]["#webform_composite_elements"]["tour_time"]["#options"] = $options['data'];
}
}
function mymodule_get_date_options(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
return $form;
}
Какой метод я должен переопределить или использовать в веб-форме экосистема, или если это вообще должно быть составным, и я могу сделать это каким-то другим способом?
1 answers
Оказывается, я был довольно близок, внешний модуль создавал помехи во время аутентификации (получал сообщение об ошибке превышения максимального размера при отправке формы) на переднем конце. Не имеет отношения к веб-форме.
Вы можете добавить ajax в составные элементы и реагировать на них в AfterBuild следующим образом (или в ваших собственных пользовательских элементах формы, добавленных в состав):
class WebformTourAvailabilityComposite extends WebformCompositeBase {
/**
* {@inheritdoc}
*/
public static function getCompositeElements(array $element) {
$date_format_entity = DateFormat::load('html_date');
$date_format = $date_format_entity->getPattern();
$elements = [];
$elements['tour_date'] = [
'#type' => 'date',
'#title' => t("Tour Date"),
'#date_date_format' => $date_format,
'#date_year_range' => '0:15',
'#attributes' => [
'min' => '[webform_submission:created:html_date]',
'onkeydown' => 'return false'
],
'#datepicker_button' => TRUE,
'#date_label_position' => 'invisible',
'#required' => TRUE,
'#ajax' => [
'callback' => ['\Drupal\mymodule\Element', 'refreshTimes'],
'wrapper' => 'available-times'
],
'#prefix' => '<div id="available-times">',
];
$elements['tour_time'] = [
'#type' => 'select',
'#title' => t('Tour time'),
'#suffix' => '</div>',
'#after_build' => [[get_called_class(), 'afterBuild']],
'#validated' => TRUE,
];
return $elements;
}
public static function refreshTimes($form, FormStateInterface $form_state) {
return $form['elements']['tour_time'];
}
/**
* Performs the after_build callback.
*/
public static function afterBuild(array $element, FormStateInterface $form_state) {
$client = \Drupal::service('mymodule.client');
$selected = $form_state->getValues();
if (isset($selected['tour_date']) && strlen($selected['tour_date'])) {
$times = $client->getAvailableTourTimes($selected["tour_date"]);
$element['#options'] = count($times) ? $times : ['' => '- Select -'];
$element['#description'] = count($times) ? '' : 'There were no available times found for the date you selected. Please choose another date.';
}
return $element;
}
}
Обратите внимание, что ключи вашей формы будут отличаться в зависимости от вашей формы, того, как вы называете поля и т.д. На AfterBuild, в данном случае, если у средства выбора даты есть отправленное значение, оно вызовет удаленный API и заменит параметры в выборе значениями.