УрокИзменение состояний формы в Drupal 7

Нередки ситуации, когда в зависимости от нажатия элемента на форме появляются/исчезают/меняются элементы этой самой формы. И если для обычных полей это можно сделать модулем conditional fields, то для своих форм придётся всё писать самому. В Друпале это можно сделать либо через ajax (об этом более подробно можно почитать тут) либо же через параметр #states в Forms API. И сейчас речь пойдёт именно о втором варианте.

Итак, #states. По сути, это PHP обёртка для простейших функций jQuery, которые изменяют состояние формы при совершении с ней заранее заданных действий.

Состояние элемента #states является ассоциативным массивом такого вида:

array(
  ELEMENT_STATE_1 => array(
    JQUERY_SELECTOR_1 => REMOTE_CONDITIONS_1,
    JQUERY_SELECTOR_2 => REMOTE_CONDITIONS_2,
  ),
  ELEMENT_STATE_2 => array(
    JQUERY_SELECTOR_3 => REMOTE_CONDITIONS_3,
  ),
)

Он состоит из набора состояний элемента, которые могут меняться при определённых состояниях других элементов страницы (селекторы можно указывать за для элементов за пределами формы!). Простейший пример:

$form['check_me'] = array(
  '#type' => 'checkbox',
  '#title' => 'Нажми на меня',
);
 
$form['toggle_element'] = array(
  '#type' => 'textfield',
  '#states' => array(
    // Элемент будет показан тогда, когда чекбокс check_me будет нажат.
    'visible' => array(
      ':input[name="check_me"]' => array('checked' => TRUE),
    ),
  ),
);

Для любителей знать, как всё работает

При добавлении в форму атрибута #states Друпал подключает библиотеку из ядра drupal.states (misc/states.js), а также добавляет к странице настройки для последующей обработки элементов. Для примера выше в коде страницы можно найти такую строку:

"states":{"#toggle_element":{"visible":{":input[name=\"check_me\"]":{"checked":true}}}

Далее библиотека drupal.states берёт эти настройки и выставляет события jQuery для выбранных селекторов.

Возможные значения состояний

Список состояний, которые могут быть применены к элементу:

  • enabled - элемент будет доступен для изменений через браузер.
  • disabled - элемент будет недоступен для изменений.
  • required - элемент станет обязательным для заполнения.
  • optional - элемент станет необязательным для заполнения.
  • visible - элемент будет показан.
  • invisible - элемент будет скрыт.
  • checked - элемент будет отмечен (нажат).
  • unchecked - с элемента снимется галочка нажатия.
  • expanded - элемент будет развёрнут (для fieldset'ов).
  • collapsed - элемент будет свёрнут (для fieldset'ов).

Список условных состояний, при которых элемент будет менять своё состояние:

  • empty - элемент пуст.
  • filled - элемент не пуст.
  • checked - элемент нажат.
  • unchecked - элемент не нажат.
  • expanded - элемент развёрнут.
  • collapsed - элемент свёрнут.
  • value - элемент имеет значение value.

Список состояний, которые могут быть применены как к элементу, так и в качестве условного состояния:

  • relevant
  • irrelevant
  • valid
  • invalid
  • touched
  • untouched
  • readwrite
  • readonly

Те, кто знаком с jQuery без труда поймут смысл перечисленных состояний. Стоит отметить, что эти атрибуты не имплементированы полностью, поэтому работы с ними в некоторых случаях может не дать никаких результатов.

Отличие переключения состояний формы через #states от работы через ajax принципиальное - в первом случае форма изначально загружается на страницу вся, однако некоторые её элементы показываются лишь при определённых условиях. В то время как в работе через ajax при загрузке страницы формы не содержит лишних элементов, они подгружаются динамически, делая ajax запрос и получая ответ от сервера.

На мой взгляд, без крайней необходимости использовать ajax не стоит. Не стоит лишний раз дёргать сервер ради загрузки нескольких элементов формы, если это по каким-либо причинам не является крайней необходимостью.

Отличный пример работы со #states можно посмотреть тут. Исходники примера располагаюются здесь.

Небольшой постскриптум.

Чем дальше развивается Друпал, тем шире становятся его границы. Я заметил за собой, что в последнее время я всё реже использую js в разработках, т.к. Друпал позволяет делать большинство действий через PHP обёртки. Он сам подключает необходимые js файлы и передаёт в параметры страницы селекторы, которые сам же потом правильным образом обрабатывает. Я доволен :)

Комментарии

Аватар пользователя Serik Yeleussizov
Serik Yeleussizov написал:

Всем доброго времени суток!
Такая проблема при выборе value selecta загружается произвольный html текст. Сам код:

$form['value']["hour"] = array (
	'#type' => 'select',
	'#options'=> array(
		0 => '09',1 => '10',2 => '11',3 => '12',4 => '13',5 => '14',6 => '15',7 => '16',8 => '17',9 => '18',10 => '19',11=>'20',12=>'21',13=>'22',
		),//при выборе свыше 19 часов загружается html текст
	'#description' => t('час'),
	'#title'=>t('Время'),
	'#size'=>1,
	'#tree' => TRUE,
	);
$form['default-item'] = array (
	'#type' => 'item',
	'#description'=> '<span class="comment">'.t('Время выселения из квартиры не позднее 19:00 часов.').'</span>',
	'#parents' => array('hour_zas'), 
    '#states' => array(
      'visible' => array(
        ':input[name="hour_zas"]' => array('value' => input_more_form_get_time())),// надо заставить чтобы при выборе value >10 загружалась данное поле
		),
);

и функция

function input_more_form_get_time() {
$op_value = $form_state['value'][$form_state["hour"]['values']];
$i==0;
$time_value = array ();
for ($op_value=0;$op_value<=15;$op_value++) {
 if($op_value>=10){ echo $time_value->$op_value;
 } break;
}
return $time_value;
}

Правильно ли моя логика? или есть альтернативы

02.05.2012 16:07
Аватар пользователя Виталий
Виталий написал:

Вроде и глупый вопрос, но не могу сделать.
На форме есть textfield, нужно его заполнить программно текстом. пробовал так:
if($form_state['values']['country_writein']==''){
$form_state['values']['country_writein']='текст';
}
но не получается. Вернее в дебаге видно, что добавило, но в самом поле не появилось. Что не так, подскажите?

20.09.2014 08:35
Аватар пользователя Дана
Дана написал:

скажите а какая форма должна быть на обратный звонок?

22.09.2016 09:48

Комментировать