динамически заполняемые CCK select list

Главные вкладки

Аватар пользователя NX-74205 NX-74205 27 декабря 2009 в 15:42

Задача:
Есть три поля CCK (типа select list)
страна, регион, город;
В БД есть соответствующие таблицы.
Я заполняю поле "Страна" из бд, к примеру так

<?php$con = db_result(db_query("SELECT COUNT(*) FROM {country}")); // выборка количества записей
$id1 = db_query("SELECT name FROM {country}"); // получаем данные
for ($i = 0; $i < $con; $i++) 
{
$result=db_result($id1,$i); // в масив их
$items[$i] = $result;
}
return $items; // возвращаем массив?>

После выбора страны, select list "Город" Должен заполниться городами, этой страны, из таблицы БД - city.
Собственно вопрос, как это реализовать?

Комментарии

Аватар пользователя NX-74205 NX-74205 27 декабря 2009 в 17:54

не вариант. с cck не работает. для 6 ки тока dev версия.
Я так предполагаю, нужно что то ajax вское делать... но вот только как...
предполагается что при выборе, каково то значения, в селект листе, должна отправлятся какая либо переменная на сервер...
вот, как реализовать отправку переменой на сервер по выбору, значения из select box

Аватар пользователя vgoodvin vgoodvin 27 декабря 2009 в 17:56

Hierarchical select хорошая вещь. Жалко что не работает с последней версией jquery. Для CCK пока такое не делал, но только что реализовал именно такой функционал в форме своего модуля. Если надо выложу код. Он не идеален, но со своей задачей справляется.

Аватар пользователя NX-74205 NX-74205 27 декабря 2009 в 18:00

да, было бы неплохо. Код, можно и доработать, если будут изменения с моей стороны, доработки итд, все вышлю вам. А возможно создам свой модуль на основе вашего, результатом так же поделюсь.
выслать можно на nnc1701e(символ собачки)mail.ru

Аватар пользователя vgoodvin vgoodvin 27 декабря 2009 в 18:02

Допустим у нас есть 2 селекта. При выборе значения в первом должны загружаться значения во второй. Следующий вариант конечно не идеален, т.к. используется массив $_POST и сначала во 2-й селект загружаются все его возможные значения. Но со своей задачей справляется.

Код формы:

  $form['location']['country'] = array(
    '#type' => 'select',
    '#title' => t('Country'),
    '#options' => array(
      '1' => t('Россия'),
      '2' => t('Кипр'),
      '3' => t('Украина'),
    ),
    '#ahah' => array(
      'path' => 'path/to/callback',
      'wrapper' => 'edit-city-container',
      'method' => 'replace',
    ),
    '#weight' => 0,
  );
  $form['location']['city'] = array(
    '#type' => 'select',
    '#title' => t('City'),
    '#options' => my_get_cities(), //Загрузка всех элементов, которые могут быть выбраны в элементе
    '#prefix' => '<div id="edit-city-container">',
    '#suffix' => '</div>',
    '#weight' => 5,
  );

Хук меню:

function my_module_menu() {
  $items['path/to/callback'] = array(
    'page callback' => 'my_print_city_options',
    'type' => MENU_CALLBACK,
    'access callback' => TRUE,
  );
 
  return $items;
}

Коллбек:

function my_print_city_options(){
  $element = array(
    '#name' => 'city',
    '#id' => 'edit-city',
    '#title' => t('City'),
    '#parents' => array('location'),
    '#options' => my_get_cities($_POST['country']),
  );
 
  print drupal_json(theme('select', $element));
  exit;
}

Функция my_get_cities:

function my_get_cities($cid = NULL){
  $sql = ($cid)?"SELECT id, name FROM {table_name} WHERE id = %d":'SELECT id, name FROM {table_name}';
  $res = db_query($sql, $cid);
  while ($row = db_fetch_object($res)){
    $options[$row->id] = $row->name;
  }

  return $options;
}

Аватар пользователя vgoodvin vgoodvin 27 декабря 2009 в 18:08

Весь модуль выкладывать не стал, т.к. этот текст по счастливому случаю у меня уже был готов, а кода в нем на несколько сотен строк поболее будет. Если с этим у вас не получится отправлю.

Аватар пользователя vgoodvin vgoodvin 10 января 2010 в 17:10

Предположим у нас 2 селекта - марки и модели автомобилей. Соответственно при выборе марки загружаются модели.

field_model - модели
field_marka - марки

В hook_form_alter:

    $form['field_model']['#prefix'] = '< div id="edit-model-container">';
    $form['field_model']['#suffix'] = '< /div>';
    $form['field_marka']['#ahah']['path'] = 'path/to/callback';
    $form['field_marka']['#ahah']['event'] = 'click';
   
    $ahah_binding = array(
      "button" => false,
      "keypress" => null,
      'url'   => url('path/to/callback'),
      'event' => 'change',
      'wrapper' => 'edit-model-container',
      'selector' => '#edit-field-marka-value',
      'effect'   => 'fade',
      'method'   => 'replace',
      'progress' => array('type' => 'throbber'),
    );
   
    drupal_add_js('misc/jquery.form.js');
    drupal_add_js('misc/ahah.js');
    drupal_add_js(array('ahah' => array('edit-field-marka-value' => $ahah_binding)), 'setting');

А вот коллбек:

<?php
function callback(){
  
$element = array(
    
'#name' => 'field_model[value]',
    
'#id' => 'edit-field-model-value',
    
'#title' => t('Model'),

    

//если элемент вложен в какой-либо контейнер заполняем массив parents
    //'#parents' => array(),

    //берем из базы массив типа id => 'value'
    

'#options' => my_get_models($_POST['field_marka']['value']),
  );
 
  print 
drupal_json(theme('select'$element));
  exit;
}
?>
Аватар пользователя vgoodvin vgoodvin 11 января 2010 в 11:42

Вот разобрал еще один метод.

У нас 2 CCK селекта - field_main и field_sub.
id формы - my_type_node_form

В первый в варианты значений занесем такой php-массив
<?phpreturn array('one', 'two', 'three');?>

Во второй
<?phpreturn array('one-one', 'two-one', 'two-two', 'three-one', 'three-two', 'three-three');?>

В модуле

/**
 * Implementation of hook_menu().
 */

function mymod_menu() {
  $items['path/to/callback'] = array(
    'page callback' => 'mymod_simple_callback',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );

  return $items;
}

/**
 * Implementation of hook_form_alter().
 */

function mymod_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    case 'my_type_node_form':
      $form['field_main']['#pre_render'][] = 'my_cck_main_field_pre_render';
      $form['#pre_render'][] = 'my_form_pre_render';
      break;
  }
}

function my_cck_main_field_pre_render($element) {
  $element['value']['#ahah'] = array(
    'event' => 'change',
    'path'    => 'path/to/callback',
    'wrapper' => 'edit-field-sub-value-wrapper',
    'method' => 'replace',
  );
 
  form_expand_ahah($element['value']);

  return $element;
}

function my_form_pre_render($form) {
  $form['field_sub']['value']['#options'] = my_return_value($form['field_main']['value']['#default_value']);

  return $form;
}

function mymod_simple_callback(){
  $element = array(
    '#name' => 'field_sub[value]',
    '#id' => 'edit-field-sub-value',
    '#title' => t('New element'),
    '#parents' => array('field_sub'),
    '#options' => my_return_value($_POST['field_main']['value']),
  );

  drupal_json(theme('select', $element));
}

function my_return_value($param){
  $items = array(
    0 => array('' => '- None -', 0 => 'one-one'),
    1 => array('' => '- None -', 1 => 'two-one', 2 => 'two-two'),
    2 => array('' => '- None -', 3 => 'three-one', 4 => 'three-two', 5 => 'three-three'),
  );
   
  return ($items[$param])?$items[$param]:array('' => '- None -');
}

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

Аватар пользователя ivan-zykov ivan-zykov 22 января 2011 в 0:14

Очень хотелось бы знать о результатах Вашей работы! Давно ищу простое решения динамических select-полей для своего сайта. К сожалению, навыками для написания скриптов не обладаю :(.

Аватар пользователя Mirocow Mirocow 22 января 2011 в 10:01

"ivan-zykov" wrote:

Недавно создал модуль облегчающий эту задачу http://95.143.220.95:85/projects/ahah-helper/repository (модуль сырой, но рабочий)
На базе этого модуля уже создал иерархию подобно Страна -> Город -> Улица -> Дом
Причем получить обработку можно на любом шаге. Все вызовы подписаны ключем, благодаря ему несложно определить какой контрол произвел вызов и передачу данных.

Аватар пользователя vgoodvin vgoodvin 22 января 2011 в 15:56

"ivan-zykov" wrote:
Очень хотелось бы знать о результатах Вашей работы! Давно ищу простое решения динамических select-полей для своего сайта. К сожалению, навыками для написания скриптов не обладаю :(.

Тогда из готового к употреблению только HierarchicalSelect.

Аватар пользователя ivan-zykov ivan-zykov 22 января 2011 в 20:44

"vgoodvin" wrote:
Тогда из готового к употреблению только HierarchicalSelect.

Было бы всё хорошо, но у меня простые cck-поля, а не таксономия.

"Mirocow" wrote:
Недавно создал модуль облегчающий эту задачу http://95.143.220.95:85/projects/ahah-helper/repository (модуль сырой, но рабочий)
На базе этого модуля уже создал иерархию подобно Страна -> Город -> Улица -> Дом
Причем получить обработку можно на любом шаге. Все вызовы подписаны ключем, благодаря ему несложно определить какой контрол произвел вызов и передачу данных.

Спасибо огромное! Знать бы теперь, как это прикручивается к Друпалу)

Аватар пользователя Mirocow Mirocow 23 января 2011 в 21:43

"ivan-zykov" wrote:
Спасибо огромное! Знать бы теперь, как это прикручивается к Друпалу)

Там 2 модуля. Один из них Demo.

Аватар пользователя vgoodvin vgoodvin 24 января 2011 в 15:53

"ivan-zykov" wrote:
Было бы всё хорошо, но у меня простые cck-поля, а не таксономия.

А с content_taxonomy не работает?

"Mirocow" wrote:
Там 2 модуля. Один из них Demo.

"ivan-zykov" wrote:
К сожалению, навыками для написания скриптов не обладаю :(