• урок
  • pantey

Form Api – часть 5. Изменение состояния элемента формы

24.02.2015

Помимо всех прочих благ, которые Form API предоставляет разработчику из «коробки», он так же может вам помочь в реализации зависимых полей. Например, нам необходимо от определенного выбранного значения одного поля, показать (скрыть) другое поле. Первое что вам может прийти в голову – это использовать JS, но и на этой случай у Form API есть свое решение. Как всегда рассмотрим это дело на примере.

Допустим, у нас есть селект, с двумя значениями и ключами 0 и 1. 0 – ключ, который используется по умолчанию (при загрузке страницы). Нам необходимо при выборе пользователем значения 1 – показать дополнительное текстовое поле. Сейчас форма у нас принимает следующий вид:

Форма с селектом и текстовым полем Сам код файла myform.module
  1. <?php
  2. /**
  3.  * implements hook_menu()
  4.  */
  5. function myform_menu(){
  6. $items = array();
  7. $items['myform'] = array(
  8. 'title' => 'Form API',
  9. 'page callback' => 'drupal_get_form',
  10. 'page arguments' => array('myform_form'),
  11. 'access callback' => TRUE
  12. );
  13.  
  14. return $items;
  15. }
  16.  
  17. /**
  18.  * Callback myform
  19.  */
  20. function myform_form($form, &$form_state) {
  21.  
  22. // Описали поле с селектом
  23. $form['field_select'] = array(
  24. '#type' => 'select',
  25. '#title' => t('Выберите значение'),
  26. '#options' => array(
  27. '0' => t('Дефолтное значение'),
  28. '1' => t('Показать дополнительное поле'),
  29. ),
  30. );
  31.  
  32. // Описали дополнительное текстовое поле
  33. $form['option_textfield'] = array(
  34. '#type' => 'textfield',
  35. '#title' => t('Дополнительное текстовое поле'),
  36. );
  37.  
  38.  
  39. // Описали кнопку отправки форму
  40. $form['submit'] = array(
  41. '#type' => 'submit', // тип поля
  42. '#value' => t('отправить форму'), // текст кнопки формы
  43. );
  44. return $form;
  45. }

Хочу заметить, мы не написали функции обработки и валидации формы, ибо в данном уроке в них нет необходимости, как это сделать вы можете прочитать здесь

Теперь приступаем к реализации нашей задачи. Здесь нам необходимо понимать, что есть два типа полей:

  • Зависимое поле
  • Влияющее поле

Зависимое поле – поле, которое принимает любое из состояний формы, например как скрытие или показ.

Влияющее поле – поле, от которого зависит состояние зависимого поля.

Итак, что бы Drupal понимал, что для зависимого поля необходимо отслеживать состояние, то для данного поля необходимо предать в массив с ключом «#states» необходимое состояние элемента формы, а так же ID влияющего поля с необходимым значением данного (влияющего) поля. На деле у нас это выглядит так:

Файл myform.module
  1. <?php
  2. /**
  3.  * implements hook_menu()
  4.  */
  5. function myform_menu(){
  6. $items = array();
  7. $items['myform'] = array(
  8. 'title' => 'Form API',
  9. 'page callback' => 'drupal_get_form',
  10. 'page arguments' => array('myform_form'),
  11. 'access callback' => TRUE
  12. );
  13.  
  14. return $items;
  15. }
  16.  
  17. /**
  18.  * Callback myform
  19.  */
  20. function myform_form($form, &$form_state) {
  21.  
  22. // Описали поле с селектом
  23. $form['field_select'] = array(
  24. '#type' => 'select',
  25. '#title' => t('Выберите значение'),
  26. '#options' => array(
  27. '0' => t('Дефолтное значение'),
  28. '1' => t('Показать дополнительное поле'),
  29. ),
  30. );
  31.  
  32. // Описали дополнительное текстовое поле
  33. $form['option_textfield'] = array(
  34. '#type' => 'textfield',
  35. '#title' => t('Дополнительное текстовое поле'),
  36. '#states' => array( // сказали Drupal, что для данного поля необходимо отслеживать состояние
  37. 'visible' => array( // указали необходимое состояние
  38. ':input[name="field_select"]' => array('value' => 1), // указали имя влияющего поля поля и его значение, при котором данное состояние должно сработать
  39. ),
  40. ),
  41. );
  42.  
  43.  
  44. // Описали кнопку отправки форму
  45. $form['submit'] = array(
  46. '#type' => 'submit', // тип поля
  47. '#value' => t('отправить форму'), // текст кнопки формы
  48. );
  49. return $form;
  50. }

Где,

  • visible – состояние формы (показать)
  • input[name="field_select"] – имя влияющего поля
  • value=>1 – значение влияющего поля

Для тех, кто активно использует Jquery, из данной конструкции все должно стать предельно ясно.

Теперь, после обновления страницы вы увидите, что у нас скрыто «дополнительное текстовое поле»

При загрузке страницы у нас скрылось дополнительное текстовое поле

А если в селекте мы выберем «Показать дополнительное поле» - то нам станет доступным текстовое поле:

Стало доступно дополнительное текстовое поле Список доступных состояний для элемента формы:
  • enabled – элемент будет доступен для редактирования. Если значение влияющего поля не выбрано, то будет добавлен атрибут disabled="disabled"
  • disabled – элемент не доступен для редактирования. Добавляет к элементу аттрибут disabled="disabled"
  • required – элемент становится обязательным для заполнения. Добавляет к label элементу формы CSS класс - form-required, в span обертке
  • optional – элемент станет не обязательным для заполнения. Если значение влияющего поля не выбрано, то к label элементу формы добавится CSS класс - form-required, в span обертке
  • visible – элемент будет показан. Если значение влияющего поля не выбрано, то элемент будет скрыт, через display:none;
  • invisible – элемент будет скрыт
  • сhecked – элемент будет отмечен, используется для элементов формы с типом checkbox и radio
  • unchecked – с элемента будет снята отметка, используется для элементов формы с типом checkbox и radio
  • expanded – элемент будет развернут, используется для элементов с типом fieldset
  • collapsed – элемент будет свернут, используется для элементов с типом fieldset

Так же существует проверка состояния влияющего поля (условное состояние), в нашем случае условным состоянием является value.

Список состояний влияющего поля:
  • empty – влияющее поле имеет пустое значение
  • filled – влияющее поле имеет не пустое значение
  • checked – влияющее поле отмечено, используется для элементов формы влияющего поля с типом checkbox и radio
  • unchecked - влияющее поле не отмечено, используется для элементов формы влияющего поля с типом checkbox и radio
  • expanded – влияющее поле развернуто, используется для элементов формы влияющего поля с типом fieldset
  • collapsed - влияющее поле не развернуто, используется для элементов формы влияющего поля с типом fieldset
  • value – влияющее поле имеет значение

Для тех кому этой информации не достаточно, то более подробно можно почитать и посмотреть примеры здесь

Теперь вы видите, что мы может отслеживать состояние элементов формы без написания дополнительного JS. На этом можно закончить.

-->
Узнавай о новых статьях сайта - первым. Просто подпишись на рассылку.

Комментарии (5)

Profile picture for user SPiRiT
Arcad
11.12.2015

А как реализовать зависимые "По содержанию" комбобоксы.
К примеру Выбор адреса. У каждого ГОРОДА свои РАЙОНЫ, у каждого района свои УЛИЦЫ, у каждой улицы свои ДОМА. Итого 4-е зависимые ПОЛЯ (как сделать их всплывающими уже понятно). Кстати АДРЕСНАЯ БАЗА находится в другой MySQL базе, это так для затравочки задачки.

Profile picture for user SPiRiT
Дмитрий
24.03.2016

Здравствуйте.
Вопрос по изменению состояния формы.
Моя форма состоит из трех отдельных чекбоксов. Пытаюсь через #states снимать отметку с активного чекбокса, если нажать на какой нибудь из двух других. Использую unchecked.
Не могу понять как внедрить условие "или". То есть мне нужно описать снятие чека, если активирован любой другой из чекбоксов. Когда пытаюсь написать что нибудь вроде

'#states' => array(
            'unchecked' => array(
                ':input[name = "medium"]' => array(
                    'checked' => TRUE
                ),
                ':input[name = "medium"]' => array(
                    'checked' => TRUE
                )
            )
        )

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

Profile picture for user pantey
pantey
24.03.2016
<?php

'#states' => array(
    'unchecked' => array(
      ':input[name = "medium"]' => array(
	array('value' => '3'),
        array('value' => '4'),
      ),
    )
  )
Profile picture for user SPiRiT
Дмитрий
24.03.2016

Вы уж простите меня, но каюсь, не понял даже принципа.
Вот форма:

$form['budget'] = array(
        '#type' => 'container',
        '#prefix' => '
', '#suffix' => '
' ); $form['budget']['name'] = array( '#type' => 'item', '#markup' => 'Бюджет' ); $form['budget']['econom'] = array( '#type' => 'checkbox', '#title' => t('Эконом'), ); $form['budget']['medium'] = array( '#type' => 'checkbox', '#title' => t('Средний'), ); $form['budget']['premium'] = array( '#type' => 'checkbox', '#title' => t('Премиум'), ); return $form;

В html каждому импуту пишется value = 1.
Вот для этого всего я пытаюсь написать #state, отключающий чек, если активируется другой чекбокс. Подскажите пожалуйста какой должен получиться принцип написания такого #states , или ткните носом где можно почитать.

Profile picture for user pantey
pantey
24.03.2016

используйте один тип для всех чекбоксов (checkboxes).