Пишу модуль. Есть три select'а. Каждый следующий должен зависеть от предыдущего. Применил свои познания в AHAH, получил следующее. Если сразу после загрузки страницы производить действия со вторым select'ом, то на нем висит событие ('change'). После того, как изменено значение в первом select'е, значения во втором изменяются и событие со второго пропадает!
После просмотра изменения кода заметил, что элементы меняются (drupal_get_form - генерит всю форму нормально, а возвращено функцией-обработчиком другое).
А именно до изменения:
<label for="edit-model-items">Модель: </label>
<select name="model_items" class="form-select" id="edit-model-items" >
<option value="1">Выберите тип в пункте выше</option>
<option value="2">Выберите тип в пункте выше</option></select>
<div class="description">Выберите модель из каталога. В скобках указано количество имеющихся экземпляров данной модели.</div>
</div>
После возврата функцией
<label>Модель: </label>
<select name="" class="form-select ahah-processed" id="edit-model-items"><optgroup label="Выберите производителя"><option value="2">Хитачи пила 1 (1)</option><option value="3">Пила 2 (2)</option></optgroup></select>
<div class="description">Выберите модель из каталога. В скобках указано количество имеющихся экземпляров данной модели.</div>
</div>
</div></div>
Как следствие пропадает действие, навешанное ранее. Не понятно, зачем внутрь элемента добавляется код, если указано в AHAH, что элемент заменяется.
Код, создающий форму (не весь, но остальной не задействуется, и не должен влиять, мне кажется
{
$simpleform = leasing_reserve_form ();
$simpleform ['leasing_reserve']['#collapsed'] = FALSE;
//Создание новых элементов формы
$result = db_query (" SELECT term_data.name, term_data.tid, COUNT( term_node.nid ) cnt
FROM term_data, term_node
WHERE term_data.tid = term_node.tid
AND term_data.vid =1
AND term_node.nid IN (SELECT id_catalog FROM {leasing_base})
GROUP BY term_data.tid
ORDER BY term_data.name ASC");
while ($obj = db_fetch_object ($result))
$type_items [$obj->tid] = $obj->name." (" . $obj->cnt . ")";
$simpleform ['leasing_reserve']['catalog_items'] = array (//Первый комбик
'#type' => 'select',
'#title' => 'Тип в каталоге',
'#description' => 'Выберите тип из каталога. В скобках указано количество моделей, которые имеются в данной категории',
'#weight' => '-3',
'#options' => array(
'Выберите производителя' => $type_items
),
'#ahah' => array (
'path' => 'leasing/getmodels',
'wrapper' => 'edit-model-items-wrapper',
'method' => 'replace'
),
);
$simpleform ['leasing_reserve']['model_items'] = array (//Второй комбик с модельками
'#type' => 'select',
'#title' => 'Модель',
'#description' => 'Выберите модель из каталога. В скобках указано количество имеющихся экземпляров данной модели.',
'#weight' => '-2',
'#options' => array (1 => 'Выберите тип в пункте выше',
2 => 'Выберите тип в пункте выше',),
'#ahah' => array (
'path' => 'leasing/getserials',
'wrapper' => 'edit-serial-items-wrapper',
),
);
$simpleform ['leasing_reserve']['serial_items'] = array (//Третий комбик с сейными номерами
'#type' => 'select',
'#title' => 'Серийный номер',
'#description' => 'Выберите серийный номер. В скобках указана цена.',
'#weight' => '-1',
'#options' => array (1 => 'Выберите тип в пункте выше',
2 => 'Выберите тип в пункте выше', ),
'#ahah' => array (
'path' => 'leasing/getprice',
'wrapper' => 'edit-price-wrapper',
),
);
$newform = $simpleform;
return $newform;
}
AHAH - обработчик события изменения в первом селекте
{
//Участок кода для правильной обрабоки формы
$form_state = array('storage' => NULL, 'submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);
$args = $form['#parameters'];
$form_id = array_shift($args);
$form['#post'] = $_POST;
$form['#redirect'] = FALSE;
$form['#programmed'] = FALSE;
$form_state['post'] = $_POST;
$form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
$file = fopen ("out.txt","w");
$str = serialize ($form);
fprintf ($file,$str);
fclose ($file);
$selectedterm = $form_state['post']['catalog_items'];
$result = db_query ("SELECT node.title, node.nid, COUNT( leasing_base.id_trade ) cnt
FROM node, leasing_base
WHERE node.nid = leasing_base.id_catalog
AND node.nid
IN (
SELECT term_node.nid
FROM term_node
WHERE term_node.tid =%d
)
GROUP BY node.nid" ,$selectedterm);
$options = '';
while ($obj = db_fetch_object ($result))
{
$model_items [$obj->nid] = $obj->title." (" . $obj->cnt . ")";
$options .= '<option value="'.$obj->nid.'">'.$obj->title.'</option>';
}
$simpleform = array (//Второй комбик с модельками
'#type' => 'select',
'#title' => 'Модель',
'#description' => 'Выберите модель из каталога. В скобках указано количество имеющихся экземпляров данной модели.',
'#weight' => '-2',
'#options' => array(
'Выберите производителя' => $model_items
),
'#ahah' => array (
'path' => 'leasing/getserials',
'wrapper' => 'edit-serial-items-wrapper',
'event' => 'change'
),
'#attributes' => array('class' => 'ahah-processed',
'id' => 'edit-model-items',
'name' => 'model-items'),
);
$javascript = drupal_add_js(NULL, NULL, 'header');
drupal_json(array(
'status' => TRUE,
'data' => theme('status_messages') . drupal_render($simpleform),
'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']),
));
$element = drupal_render ($simpleform);
//return drupal_json ($element);
return $element;
}
Буду очень признателен за ответ на вопрос.
Комментарии
{
//Участок кода для правильной обрабоки формы
$form_state = array('storage' => NULL, 'submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);
$args = $form['#parameters'];
$form_id = array_shift($args);
$form['#post'] = $_POST;
$form['#redirect'] = FALSE;
$form['#programmed'] = FALSE;
$form_state['post'] = $_POST;
$form = form_builder($form_id, $form, $form_state);
$file = fopen ("out.txt","w");
$str = serialize ($form);
fprintf ($file,$str);
fclose ($file);
$selectedterm = $form_state['post']['catalog_items'];
$result = db_query ("SELECT node.title, node.nid, COUNT( leasing_base.id_trade ) cnt
FROM node, leasing_base
WHERE node.nid = leasing_base.id_catalog
AND node.nid
IN (
SELECT term_node.nid
FROM term_node
WHERE term_node.tid =%d
)
GROUP BY node.nid" ,$selectedterm);
//$options = '';
$options = array();
while ($obj = db_fetch_object ($result))
{
//$model_items [$obj->nid] = $obj->title." (" . $obj->cnt . ")";
$options[$obj->nid] = $obj->title." (" . $obj->cnt . ")";
}
$simpleform = $form['leasing_reserve']['model_items'];
$simplaform['#options'] = $options;
$javascript = drupal_add_js(NULL, NULL, 'header');
drupal_json(array(
'status' => TRUE,
'data' => theme('status_messages') . drupal_render($simpleform),
'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']),
));
$element = drupal_render ($simpleform);
//return drupal_json ($element);
print drupal_to_js(array('status' => TRUE, 'data' => $element));
exit;
}
Примерно так. Хотя лучше прямо в функции определения формы динамически высчитывать опции и дефолтные значения селектов, тогда форма сгенерируется сама верно, например при редактировании и с отключенным js тоже работать будет, а так не будет.
gorr, а можно объяснить, что конкретно было у меня не правильно? И в чем состоят изменения?
Тупое копирование кода не помогло, модификация его тоже результатов не дает.
Изменения следующие - в drupal_rebuild_form форма проходит обработку, вызываются валидаторы, итд, форма заново генерится, в данном случае это не нужно. Можно построить ее с помощью form_builder, вынув из кеша, при этом передав необходимые полученные данные от клиента(#post). Далее просто берем необходимый для замены элемент из уже имеющегося массива формы, а не прописываем его заново и, раз уж мы не сделали динамические опции в функции задающей массив формы, то генерируем их здесь, хотя это неверно(уже писал почему).
А что теперь выдает, какой код получается?
И еще, все-таки обычно элементу, который динамически надо заменять обычно прописывают префикс и суффикс(оборачивающий див) и указывают его в качестве враппера в ахах элементе.
Возможно еще сбой дает то, что элемент leasing_reserve не прописан, во всяком случае я не вижу в определении формы его опиания, кроме $simpleform ['leasing_reserve'].['#collapsed'] = FALSE;
Итак, проблема с одной стороны решена, а с другой нет
Получившийся код на стороне клиента:
<div><div class="form-item" id="edit-model-items-wrapper">
<label for="edit-model-items">Модель: </label>
<select name="model_items" class="form-select ahah-processed progress-disabled" id="edit-model-items">
<option value="2">Хитачи пила 1 (1)</option><option value="3">Пила 2 (2)</option></select>
<div class="description">Выберите модель из каталога. В скобках указано количество имеющихся экземпляров данной модели.</div>
</div>
</div></div>
На странице появились 2 элемента с одинаковыми ID. Но теперь код возвращает правильное значение (события срабатывают - не знаю как, но это факт).
Вот рабочая функция (точнее она работает, после неё последствия лишнего кода нейтрализуются, но не решается проблема в теме - лишний html остается)
{
//Участок кода для правильной обрабоки формы
$form_state = array('storage' => NULL, 'submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);
$args = $form['#parameters'];
$form_id = array_shift($args);
$form['#post'] = $_POST;
$form['#redirect'] = FALSE;
$form['#programmed'] = FALSE;
$form_state['post'] = $_POST;
$form = form_builder($form_id, $form, $form_state);
$file = fopen ("out.txt","w");
$str = serialize ($form);
fprintf ($file,$str);
fclose ($file);
$selectedterm = $form_state['post']['catalog_items'];
$result = db_query ("SELECT node.title, node.nid, COUNT( leasing_base.id_trade ) cnt
FROM node, leasing_base
WHERE node.nid = leasing_base.id_catalog
AND node.nid
IN (
SELECT term_node.nid
FROM term_node
WHERE term_node.tid =%d
)
GROUP BY node.nid" ,$selectedterm);
$options = array();
while ($obj = db_fetch_object ($result))
{
//$model_items [$obj->nid] = $obj->title." (" . $obj->cnt . ")";
$options[$obj->nid] = $obj->title." (" . $obj->cnt . ")";
}
$simpleform = $form['leasing_reserve']['model_items'];
$simpleform['#options'] = $options;
$javascript = drupal_add_js(NULL, NULL, 'header');
return drupal_json(array(
'status' => TRUE,
'data' => theme('status_messages') . drupal_render($simpleform),
'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']),
));
}
В коде это есть. Там вызывается другая функция, она возвращает код формы на блок. С этим хорошо.
Gorr, большое спасибо!!! Я с середины прошлой недели над этим голову ломаю. Но тему пока не закрываю, вроде бы решение не соответствует заголовку. Зато работает!
Если надо заменить элемент новым, то надо в определении элемента добавить метод "заменить" к ахах атрибутам:
'#ahah' => array('method' => 'replace')
Но в данном случае это не поможет наверное, просто сначала не понял о чем речь и подумал, что появляются 2 одинаковых элемента в форме.
А здесь не то, просто лишний оборачивающий див..повторюсь - прописывайте явно врапперы для заменяемых элементов. Ну или выкусить из вывода лишнее, но обычно такого не происходит.