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

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

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

В этом примере покажу, как можно создать зависимые списки терминов таксономии на 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
Похожие записи

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

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

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

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

http://xandeadx.ru/blog/drupal/304

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Добрый день!
Весь код в примере понятен, уже переделал его под свои нужды, но один момент мне не понятен. Код $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'] будут значения всех трёх

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

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

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

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

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

http://pastebin.com/faRk7sR9

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

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

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

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

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

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

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

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

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

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

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

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

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

@Алексей читайте про ajax формы

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

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

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

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

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

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

taxonomy_get_tree(1, $parent_tid, 1)

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

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

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

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

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

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

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

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

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

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

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

если $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';// второй селект хоть и получил значение по умолчанию но сам не загрузился

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

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

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

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

Auman
Bentley
BMW
BYD

option value="7454">AumanBentleyBMWBYD

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

Добрый день

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

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

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

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

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

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

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