[Решено] Снова AHAH: лишний и неправильный возвращенный код

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

Аватар пользователя vitg vitg 13 июля 2010 в 8:50

Пишу модуль. Есть три select'а. Каждый следующий должен зависеть от предыдущего. Применил свои познания в AHAH, получил следующее. Если сразу после загрузки страницы производить действия со вторым select'ом, то на нем висит событие ('change'). После того, как изменено значение в первом select'е, значения во втором изменяются и событие со второго пропадает!
После просмотра изменения кода заметил, что элементы меняются (drupal_get_form - генерит всю форму нормально, а возвращено функцией-обработчиком другое).
А именно до изменения:

<div class="form-item" id="edit-model-items-wrapper">
 <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>

После возврата функцией

<div class="form-item" id="edit-model-items-wrapper"><div><div class="form-item">
 <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, что элемент заменяется.

Код, создающий форму (не весь, но остальной не задействуется, и не должен влиять, мне кажется

function leasing_page_form ()
{
        $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 - обработчик события изменения в первом селекте

function get_model_items ()
{

        //Участок кода для правильной обрабоки формы
        $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;

}

Буду очень признателен за ответ на вопрос.

Комментарии

Аватар пользователя gorr gorr 13 июля 2010 в 15:13
function get_model_items ()
{
 
        //Участок кода для правильной обрабоки формы
        $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 тоже работать будет, а так не будет.

Аватар пользователя vitg vitg 13 июля 2010 в 16:45

gorr, а можно объяснить, что конкретно было у меня не правильно? И в чем состоят изменения?

Тупое копирование кода не помогло, модификация его тоже результатов не дает.

Аватар пользователя gorr gorr 13 июля 2010 в 17:14

Изменения следующие - в drupal_rebuild_form форма проходит обработку, вызываются валидаторы, итд, форма заново генерится, в данном случае это не нужно. Можно построить ее с помощью form_builder, вынув из кеша, при этом передав необходимые полученные данные от клиента(#post). Далее просто берем необходимый для замены элемент из уже имеющегося массива формы, а не прописываем его заново и, раз уж мы не сделали динамические опции в функции задающей массив формы, то генерируем их здесь, хотя это неверно(уже писал почему).
А что теперь выдает, какой код получается?
И еще, все-таки обычно элементу, который динамически надо заменять обычно прописывают префикс и суффикс(оборачивающий див) и указывают его в качестве враппера в ахах элементе.

Аватар пользователя gorr gorr 13 июля 2010 в 17:17

Возможно еще сбой дает то, что элемент leasing_reserve не прописан, во всяком случае я не вижу в определении формы его опиания, кроме $simpleform ['leasing_reserve'].['#collapsed'] = FALSE;

Аватар пользователя vitg vitg 13 июля 2010 в 17:46

Итак, проблема с одной стороны решена, а с другой нет
Получившийся код на стороне клиента:

<div class="form-item" id="edit-model-items-wrapper">
<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 остается)

function get_model_items ()
{

        //Участок кода для правильной обрабоки формы
        $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" wrote:
leasing_reserve не прописан

В коде это есть. Там вызывается другая функция, она возвращает код формы на блок. С этим хорошо.

Gorr, большое спасибо!!! Я с середины прошлой недели над этим голову ломаю. Но тему пока не закрываю, вроде бы решение не соответствует заголовку. Зато работает!

Аватар пользователя gorr gorr 13 июля 2010 в 18:02

Если надо заменить элемент новым, то надо в определении элемента добавить метод "заменить" к ахах атрибутам:
'#ahah' => array('method' => 'replace')
Но в данном случае это не поможет наверное, просто сначала не понял о чем речь и подумал, что появляются 2 одинаковых элемента в форме.
А здесь не то, просто лишний оборачивающий див..повторюсь - прописывайте явно врапперы для заменяемых элементов. Ну или выкусить из вывода лишнее, но обычно такого не происходит.