Drupal → Правильные ajax селекты, чекбоксы и радиокнопки

13.02.2014

Я как-то писал как добавлять элементы в форму с помощью AJAX. Форма работала, но у неё был один недостаток — элементы добавлялись только при включённом javascript.

Сложность реализации ajax селектов/радиокнопок/чекбоксов в том, что без javascript нет возможности засабмитить форму и следовательно изменить её элементы.

Решение достаточно простое — добавить кнопку, видимую только пользователям с отключённым js. Кнопка будет сабмитить форму и добавлять элементы, а select, с помощью свойства #ajax['trigger_as'] будет эмулировать нажатие кнопки:

1. Создаём форму работающую без javascript

/**
 * Form builder.
 */
function helper_form_test($form, &$form_state) {
  $form['fields_count_wrapper'] = array(
    '#type' => 'container',
  );
  
  // Селект с числом полей
  $form['fields_count_wrapper']['fields_count'] = array(
    '#type' => 'select',
    '#title' => 'Fields count',
    '#options' => drupal_map_assoc(array(1, 2, 3)),
  );
  
  // Кнопка для изменения числа полей в форме
  $form['fields_count_wrapper']['fields_count_change'] = array(
    '#type' => 'submit',
    '#value' => 'Change count',
    // При отправки формы с помощью этой кнопки, валидацию будет проходить только поле fields_count
    '#limit_validation_errors' => array(
      array('fields_count'),
    ),
    '#submit' => array('helper_form_test_fields_count_change'),
  );
  
  // Число полей зависит от выбранного значения в fields_count
  $count = isset($form_state['values']['fields_count']) ? $form_state['values']['fields_count'] : 1;
  for ($i = 0; $i < $count; $i++) {
    $form['fields']['field' . $i] = array(
      '#type' => 'textfield',
      '#title' => 'Field ' . ($i + 1),
      '#required' => TRUE,
    );
  }
  
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  
  return $form;
}

/**
 * Change count callback.
 */
function helper_form_test_fields_count_change($form, &$form_state) {
  $form_state['rebuild'] = TRUE;
}

/**
 * Submit callback.
 */
function helper_form_test_submit($form, &$form_state) {
  // ...
}

2. Добавляем ajax функционал кнопке fields_count_change

/**
 * Form builder.
 */
function helper_form_test($form, &$form_state) {
  // ...
  
  $form['fields_count_wrapper']['fields_count_change'] = array(
    // ...
    // AJAX функционал
    '#ajax' => array(
      'callback' => 'helper_form_test_fields_count_change_ajax',
      'wrapper' => 'fields',
    ),
  );
  
  $form['fields'] = array(
    '#prefix' => '<div id="fields">',
    '#suffix' => '</div>',
  );
  
  // ...
}

/**
 * Ajax callback.
 */
function helper_form_test_fields_count_change_ajax($form, &$form_state) {
  return $form['fields'];
}

3. Добавляем ajax функционал селекту fields_count и скрываем кнопку fields_count_change

/**
 * Form builder.
 */
function helper_form_test($form, &$form_state) {
  // ...
  
  $form['fields_count_wrapper']['fields_count'] = array(
    // ...
    // AJAX функционал
    '#ajax' => array(
      'callback' => '',
      'wrapper' => 'fields',
      'trigger_as' => array('name' => 'fields_count_change'),
    ),
  );

  $form['fields_count_wrapper']['fields_count_change'] = array(
    // ...
    // Скрываем кнопку
    '#attributes' => array(
      'class' => array('js-hide'),
    ),
  );
  
  // ...
}

В этом пункте есть небольшой подводный камень — #ajax у селекта не будет работать без свойства callback (его нужно оставить пустым) и без wrapper (его нужно продублировать из $form['fields_count_wrapper']['fields_count_change']['#ajax']['wrapper']).

Исходники.

Видео работы:

без ajax
с ajax кнопкой
с ajax селектом

Написанное актуально для
Drupal 7
Похожие записи

Комментарии

Алекс Шут
27.11.2015, 00:48

Мне нужно, чтобы форма отрабатывала по клику на одном из чекеров.
Ну есть кучка чекеров. Клик по одному - форма отработала. Без кнопки сабмита.
Верно понял, что вариант с ajax селектом - самое оно, что мне нужно. И можно ли обойтись без ajax в принципе?

без кнопки форму нельзя отправить

Алекс Шут
27.11.2015, 04:13

И ничего не наколдовать? =(

Алекс Шут
27.11.2015, 14:48

Лол. я же и уточняю. Твой пример с ajax селектом - аккурат тот случай? ))

не понимаю какой "тот случай", формы можно делать как с ajax так и без

Алекс Шут
27.11.2015, 17:32

В смысле, спрятать кнопку сабмита и отрабатывать форму по тыцанию в който произвольно выбранный чекер. Уже понял, что таки оно. Накопалась еще парочка примеров. Осталось не тупить )

Роман
03.02.2016, 20:02

Скажите пожалуйста, а если на форме много элементов select и они отрабатываются по ajax через submit-кнопку, то можно ли в submit-функции каким-то образом узнать, какой из select-элементов был задействован ?
$form_state['triggering_element'] в этом случае возвращает submit-кнопку, а не select.

Гость
27.10.2018, 16:31

Подскажите, а "с помощью свойства #ajax['trigger_as'] будет эмулировать нажатие кнопки:" для д8 тоже должно работать?

Добавить комментарий