xandeadx.ru Блог музицирующего веб-девелопера

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

Опубликовано в

Я как-то писал как добавлять элементы в форму с помощью 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
Похожие записи

Комментарии RSS

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

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

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

ajax

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

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

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

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

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании