Drupal → Пишем свой аналог Hierarchical Select на Form API + AJAX Framework (зависимые списки терминов таксономии)

26.09.2011

В этом примере покажу, как можно создать зависимые списки терминов таксономии на Form API и AJAX.

Имеем словарь (vid=1):

Термины словаря

Нужно создать форму по подобию Hierarchical Select, в которой при выборе значения в одном селекте, рядом будет появляться ещё один с дочерними терминами:

Код:

/**
 * Форма
 */
function mymodule_test_form($form, $form_state) {
  // Враппер для селектов
  $form['terms'] = array(
    '#tree' => TRUE, 
    '#prefix' => '<div id="terms">', 
    '#suffix' => '</div>', 
  );
  
  // Если сработает AJAX, то в $form_state['values']['terms'] будут выбранные значения селектов
  $terms_values = isset($form_state['values']['terms']) ? $form_state['values']['terms'] : array();
  // Селектов будет генерится на 1 больше чем есть в $form_state['values']['terms']
  $terms_values += array('term' . (count($terms_values) + 1) => 'none');
  // В первом селекте будут выводится термины без родителя
  $parent_tid = 0; 

  foreach ($terms_values as $input_name => $tid) {
    // Завершаем цикл если в предыдущем селекте ничего не выбрано
    // или у термина нет дочерних терминов
    if ($parent_tid === 'none' || !($terms = taxonomy_get_tree(1, $parent_tid, 1))) {
      break;
    }
    
    // Формируем данные для селекта
    $options = array('none' => '<none>');
    foreach ($terms as $term) {
      $options[$term->tid] = $term->name;
    }
    
    // Создаём сам селект
    $form['terms'][$input_name] = array(
      '#type' => 'select',
      '#options' => $options,
      '#default_value' => $tid,
      '#ajax' => array(
        'callback' => 'mymodule_test_form_ajax_callback',
        'wrapper' => 'terms',
      ),
    );
    
    $parent_tid = isset($options[$tid]) ? $tid : 'none';
  }
  
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  
  return $form;
}

/**
 * AJAX callback
 */
function mymodule_test_form_ajax_callback($form, $form_state) {
  return $form['terms'];
}

Исходники.

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

Комментарии

Если в кол-во терминов в словаре не очень большое, то удобней такой селект делать без ajax.

chyvakoff
26.09.2011, 10:29

А что за дебагер на видеоролике?

Гость
26.09.2011, 14:59

блин, как раз сейчас озадачен таким селектом, только нужно изначально селект с основными городами, а подгружать регионы/второстепенные города, буду копать...

Vydrin_AP
26.09.2011, 15:35

блин, как раз сейчас озадачен таким селектом, только нужно изначально селект с основными городами, а подгружать регионы/второстепенные города, буду копать...

http://xandeadx.ru/blog/javascript/36

Гость
26.09.2011, 16:28

блин, как раз сейчас озадачен таким селектом, только нужно изначально селект с основными городами, а подгружать регионы/второстепенные города, буду копать...

http://xandeadx.ru/blog/javascript/36

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

Гость
30.10.2011, 18:04

подскажите пожалуйста как это заставить работать на друпал7 куда все это дело вставляется.
Я хочу это вывести в блоке справа, когда пишу весь этот код в page.tpl.php в оответствующем месте, то получаю 500 ошибку.

Гость
17.11.2011, 21:59

Отличный пример.
а есть какие либо варианты под 6ю ветку?

пишу модуль под 6ку по работе с КЛАДР (база такая)...
пот и застрял с зависимой выборкой.
Использую ahah. но заставить грузиться дальше второго списка не вышло..

заранее спасибо.

Гость
18.07.2012, 12:47

Здравствуйте, не могу заставить данный код работать, создается первый селект и дальше ничего не происходит

При попытке разрушения уже существующего поля select и создания заново (с таким же именем) - всё работает, но данные по этому полю (значение выбранное в последнем селекте) в базу не записываются. Как быть?

Гость
28.08.2012, 12:12

Прошу прощения, я с друпал пока на Вы.
Так и не понял как заставить работать сей код...
В директории sites\all\modules создал папку mymodule, в ней два файла .module и .info. Код в файле имя.module... В админ. Drupal'a мой модуль виден, включается, но на этом всё... Т.е. ни каких ошибок нет, но и так же нет ни где его вывода...

Дмитрий
10.09.2012, 10:45

Можно создать свое поле типа "taxonomy_hierarhical_select" и оформить его в модуль.

Гость
22.09.2012, 15:18

Спасибо за пример. Все отлично работает.

Добрый день!
Весь код в примере понятен, уже переделал его под свои нужды, но один момент мне не понятен. Код $parent = isset($options[$tid]) ? $tid : 'none'; на сколько я понял, проверяет передается ли какое-нибудь значение из выбранного селекта, и если передается, то $parent присваивается это значение. Но как это работает, ведь по идее в $options храниться массив значений доступных для данного селекта. Где ключами будет будет tid термина (то есть числа 3, 4, 5 ...23), а значениями имя термина (Вася, Коля, Петя). Причем в переменной $tid будет храниться значение по умолчанию(например Коля).А теперь мы берем и проверяем существует ли такой элемент, при этом передавая в запись $options[$tid] вместо ключа, значение по умолчанию. Как это работает, не пойму?

я сократил код, возможно в ущерб читабельности, ибо сам уже еле вспомнил зачем эта проверка :) можно было написать так:

if (isset($options[$tid])) {
  $parent = $tid;
}
else {
  break;
}

если написать просто $parent = $tid;, то возможно ситуация, когда юзер нащёлкал три селекта и изменил значение в первом, то третий селект останется, потому что в $form_state['values']['terms'] будут значения всех трёх

Гость
07.10.2012, 00:54

Отличный пример, главное - рабочий и нужный!
Подскажите, а как сделать чтобы обе формы (родительская и дочерняя) отображались даже при значении родительского селекта 'none', но только чтобы дочерняя форма в этом случае была с атрибутом disabled?
И как прописать название дочерней формы отличное от родительской, например, "область" - родительская форма, а "город" - дочерняя, ибо в данном примере, если задать заголовок родительской форме, то он автоматом присваиваеится и дочерней?

Гость
07.10.2012, 01:10

Жалко редактировать свои сообщения нельзя, в общем второй вопрос насчет названия форм решил сам:

....
    // Создаём сам селект
    $form['terms'][$input_name] = array(
      '#title' => $parent_tid == 'none' ? t('Region') : t('Town'),  // Добавил

а вот с первым вопросом, походу, сам вряд ли разберусь...

Гость
13.10.2012, 22:14

По поводу первого вопроса (Гость, вс 07/10/2012 - 00:54) насчет неактивного второго селекта формы при условии что в родительской форме ничего не выбрано (собственно код тестового модуля example_hs):

http://pastebin.com/faRk7sR9

В итоге вроде бы в тестовом варианте работет нормально, но криво все это, хотелось бы универсальнее, как у Вас, с независимостью от вложенности...
Есть идеи?!

Гость
13.01.2013, 14:30

Прошу прощения, я с друпал пока на Вы.
Так и не понял как заставить работать сей код...
В директории sites\all\modules создал папку mymodule, в ней два файла .module и .info. Код в файле имя.module... В админ. Drupal'a мой модуль виден, включается, но на этом всё... Т.е. ни каких ошибок нет, но и так же нет ни где его вывода...
Дмитрий, Пнд 10/09/2012 - 10:45 #

Можно создать свое поле типа "taxonomy_hierarhical_select" и оформить его в модуль.

Что имеется ввиду и как это реализовать?
И ещё очень важный вопрос, как добавить зависимые списки в уже существующую вьюху???

Дмитрий
13.01.2013, 14:42

Прошу прощения, я с друпал пока на Вы.
Так и не понял как заставить работать сей код...
В директории sites\all\modules создал папку mymodule, в ней два файла .module и .info. Код в файле имя.module... В админ. Drupal'a мой модуль виден, включается, но на этом всё... Т.е. ни каких ошибок нет, но и так же нет ни где его вывода...
Дмитрий, Пнд 10/09/2012 - 10:45 #

Можно создать свое поле типа "taxonomy_hierarhical_select" и оформить его в модуль.
Что имеется ввиду и как это реализовать?

И ещё очень важный вопрос, как добавить зависимые списки в уже существующую вьюху???

Это вопрос не на раз-два и ответил. Нужно почитать в интернете, но если вы с друпалом на "вы" то лучше заказать этот функционал у профессионального разработчика.

Гость
13.01.2013, 14:58

Может дадите ссылку на ресурс, где можно почитать об этом!

Гость
16.01.2013, 17:09

зависимые списки прекрасно работают.
Не подскажите, как создать такой же вывод зависимых списков только в Типе содержимого?
(создал тип содержимого, тип поля-ссылка на термин, виджет-иерархический выбор) ужасно работает. Что можно придумать?
Версия: Друпал 7.
Спасибо.

А как добавить такое поле в ноду? И чтобы оно работало с API друпала*

Гость
31.01.2013, 14:09

Скажите пожалуйста, как привязать эту форму к странице? создал модуль, что дальше?

Алексей
09.02.2013, 21:23

Здравствуйте!
xandeadx, подскажите пожалуйста у меня есть поле "цена", которое имеет суффикс "ххх" как сделать чтобы суффикс динамически менялся на "ууу" т.е. есть поле список "тип сделки", есть поле "цена". Мне нужно в зависимости от типа сделки менялся суффикс. Пробовал через states api создать 2 поля разными суффиксами, но меня не очень устраивает такой вариант

Гость
19.02.2013, 03:47

Как это реализовать для vid=2 и уже существующего поля.

Гость
28.02.2013, 12:21

Нужный модуль Уже поставил. Скажите пожалуйста!
Как добавить переместить данный модуль в блок и сделать так, чтобы после SUBMIT отправляло на страницу с последним термином?
Спасибо за ответ!

Алексей
16.08.2013, 18:57

А как всё это прикрутить к форме создания конкретного типа материала?

Почему при включение модуля из исходников, модуль не работает. Полей просто напрасто нету на старнице Example Hierarchical Select

Слава
12.09.2013, 17:03

Почему при включение модуля из исходников, модуль не работает. Полей просто напрасто нету на странице Example Hierarchical Select

+1. Только кнопка Submit
Автор похоже забыл сказать, что в функции

taxonomy_get_tree(1, $parent_tid, 1)

захардкодил первым аргументом $vid словаря, из которого будут вытягиваться термины. В общем добавьте вместо 1 (первого аргумента) $vid вашего словаря (таблица taxonomy_vocabulary) и все будет работать.
А вообще за пример спасибо!

Александр
13.11.2013, 13:49

Подскажите, пожалуйста, как в третьем селекте вывести ноды, привязанные к терминам второго селекта? Ну очень буду благодарен))) с меня пиво....)) надо оооочень....

Александр
14.11.2013, 00:02

сделал по-своему.... сквозь терни.. в 2 этапа... сначала по примеру выбирается термин.. на другой странице в список загружаю ноды принадлежащие "term2"... как ноды по термину загрузить тоже на этом сайте нашел.... и там уже манипулирую с ними.. красивее не могу придумать))) но работает!!! огромное спасибо Автору!! есть ведь люди которые не только для себя все делают... делятся с другими... респект.. я не такой... мне лень что-то делать НЕ для себя....

Гость
07.01.2014, 13:11

Как быть, если у меня 3 уровня терминов и нужно чтоб "#default_value" = 6 (термин из 3-го уровня)?

Андрей
19.03.2014, 16:34

Есть hook_form_alter и ajax_callback, замещающий элемент формы через $commands:
$commands[] = ajax_command_html('#prefix1', render($form['dropdown1']));
Но при установке нового #default_value в hook_form_alter, оно не отрендеривается через этот render в ajax_callback. Намекните, пожалуйста, сломал голову уже.

Андрей
19.03.2014, 16:40

и форма объявлена в hook_form_alter как &$form...

Андрей
21.03.2014, 09:40

Сделал через кастомный Drupal.ajax.prototype.command в js через явное проставление val в js. Странно, что установка $form_state['values'] не помогает в ajax_callback'е...

Александр
15.07.2014, 05:08

Спасибо за модуль. Насколько я понял все модули HS сделаны под форму "add/edit" - а если этот может работать просто в ноде -то это Очень нужная вешь.
Так подскажите как модуль использовать в ноде. Самотаятельно я его в поле не оберну это точно. http://internetdevels.ru/blog/module-with-field-api-drupal-7 - не совсем понятно как из модуля сделать модуль поля.
Может каким-то другим способом его можно вызвать?

это не модуль, это пример работы с ajax

Александр
15.07.2014, 13:06

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

Александр
22.08.2014, 03:56

почти разобрался с селектом,
спасибо за комменты, - можно разобраться как и что работает

если $options[$term->tid] = $term->name;
заменить на
$options[$term->tid] = i18n_taxonomy_term_name($term, $language->language);
то переведенные термины будут работать

одно не понятно как указать значения по умолчанию дле многоуровневого словаря
$form['terms']['term1']['#default_value'] = '1323'; // первый селект устанавливаестся как нужно, так как уже загружен
$form['terms']['term2']['#default_value'] = '3';// второй селект хоть и получил значение по умолчанию но сам не загрузился

как имитировать выбор следующих селектов или просто их загрузить их наперед?

Гость
17.09.2014, 12:40

У меня тоже проблемы с #default_value (3 уровня вложенности).

Гость
03.10.2014, 13:28

Статья весьма полезна. Для своих нужд реализовала форму, подскажите как теперь записать данные из формы?
array (
'terms' =>
array (
'term1' => '7454',
'term2' => '7455',
),

мне необходимо зная ключ присвоить переменной имя (например зная ключ 'term1' => '7454', переменной $str присваиваем значение 'Auman' и записываем его в файл fputs ( $file, $str);)

Auman
Bentley
BMW
BYD

Гость
07.05.2015, 03:58

Добрый день. Который день мучаюсь, но никак не соображу:
Как сделать обязательным выбор самого глубокого термина?
Без этого работает отлично, но нужна возможность реализации именно здесь. Если кто-либо делал или есть мысли - отзовитесь плиз!!!
P.S. Автор молодец. Один из самых лучших сайтов о drupal и с хорошими примерами

Гость
21.02.2016, 16:29

Добрый день

Скажите, а как быть если необходимо множественное значение ?

По виду это должно выглядеть так:
https://www.drupal.org/project/multiple_selects

Программно использовать виджет из модуля не удалось.

А ваш вариант, кажется, уже обсуждали на дорге, если не ошибаюсь, там писали про ограничения form api.

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