Добавьте событие #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;
}

Какой метод я должен переопределить или использовать в веб-форме экосистема, или если это вообще должно быть составным, и я могу сделать это каким-то другим способом?

 2
Author: kiamlaluno, 2021-01-06

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 и заменит параметры в выборе значениями.

 0
Author: Kevin, 2021-01-12 14:58:56