Я довольно редко читаю что-то на русском. Чаще хэндбук и ишью трэкер на d org ну и в исходниках роюсь, разумеется. Однако, подходящих исходников пока не нашел.
Вобще, я пытаюсь сделать пару селектов, один из которых зависит от другого а-ля Страна —> Город (наираспространеннейшая задача)
И на текущий момент у меня остался один вопрос: как перестроить форму в функции ahah callback в обход валидации всех полей.
Думаю, если бы вы были в теме, фразы «перестроить форму в обход валидации всех полей» было бы более чем достаточно )
В общем-то это не пост-вопрос, это скорее крик души — нужно было как-то разрядиться ))
Но если в кратце, то проблема в следующем.
Задача: сделать зависимый селект без перезагрузки формы (а-ля ajax)
Решение:
Посколько друпал не лыком шит и с формами работает очень хитро, задача из тривиальной (отправить ajax-запрос при изменении родительского селекта, обработать запрос на сервере, отправить обратно отрендеренный селект, вставить в нужное место и готово) — превращается в непростую. Как известно, друпал хранит кэш формы (массива, определяющего структуру формы) для целей безопасности. Соответственно менять HTML-форму напрямую с помощью JS, как все привыкли, бесполезно — получим ошибку при сабмите (Illegal что-то там...). Поэтому ajax-запрос инициирует перестройку формы на сервере (достать из кэша, отпроцессить, построить) и только после этого выдирает из перестроенной формы нужный кусок, рендерит его и отправляет клиенту.
Но проблема в том, что при процессинге формы выполняется ей полная валидация и соответственно мы получает кучу ошибок на каждое незаполненное обязательно поле, которые нам на данном этапе вовсе не нужны. Соответственно вопрос в том, как перестроить форму в обход валидации.
Чтоб было совсем уж наглядно, приведу здесь пример самой типичоной ahah callback функции.
<?php function ahah_example_select_type_ahah() { // this part is used to set up $form_state. // In Drupal 7, these next 11 lines will be put in a core utility function. // Just remember you'll need them in D6 when you do AHAH! $form_state = array('storage' => NULL, 'submitted' => FALSE); $form_build_id = $_POST['form_build_id'];
// From here on, we start our own code. // We just get the element of $form that needs to be refreshed, and just resubmit that // part through the json call. In this case we want to replace the 'kind' <div> wrapper and it's // containing select box $changed_elements = $form['animals_kind']; unset($changed_elements['#prefix'], $changed_elements['suffix']); // we'll unset the div to make sure it won't be repeated! // the actual JSON call $javascript = drupal_add_js(NULL, NULL, 'header'); drupal_json(array( 'status' => TRUE, 'data' => theme('status_messages') . drupal_render($changed_elements), // rebuild just the part that needs to be changed 'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']), )); } ?>
2Nikit: простите, был не прав
2Gorr: спасибо! Как раз это решение я и собираюсь использовать (вот отсюда http://drupal.org/node/524220), хоть такой способ и считается «некрасивым», похоже придется на нем остановится.
А почему не красиво? В Вашем случае процесс_форм ведь не нужен. Для poll модуля он обязателен, потому, что там на этом работа формы заканчивается - пользователь отдал голос, больше форма не нужна. Ему показываются результаты предыдущих голосований, к примеру. Поэтому ее там обязательно надо валидировать и сабмитить. А тут вроде нет, или я что-то не учел?
Комментарии
читайте исходные тексты, а не на русском
Я довольно редко читаю что-то на русском. Чаще хэндбук и ишью трэкер на d org ну и в исходниках роюсь, разумеется. Однако, подходящих исходников пока не нашел.
Вобще, я пытаюсь сделать пару селектов, один из которых зависит от другого а-ля Страна —> Город (наираспространеннейшая задача)
И на текущий момент у меня остался один вопрос: как перестроить форму в функции ahah callback в обход валидации всех полей.
огласите проблему поподробнее.
Думаю, если бы вы были в теме, фразы «перестроить форму в обход валидации всех полей» было бы более чем достаточно )
В общем-то это не пост-вопрос, это скорее крик души — нужно было как-то разрядиться ))
Но если в кратце, то проблема в следующем.
Задача: сделать зависимый селект без перезагрузки формы (а-ля ajax)
Решение:
Посколько друпал не лыком шит и с формами работает очень хитро, задача из тривиальной (отправить ajax-запрос при изменении родительского селекта, обработать запрос на сервере, отправить обратно отрендеренный селект, вставить в нужное место и готово) — превращается в непростую. Как известно, друпал хранит кэш формы (массива, определяющего структуру формы) для целей безопасности. Соответственно менять HTML-форму напрямую с помощью JS, как все привыкли, бесполезно — получим ошибку при сабмите (Illegal что-то там...). Поэтому ajax-запрос инициирует перестройку формы на сервере (достать из кэша, отпроцессить, построить) и только после этого выдирает из перестроенной формы нужный кусок, рендерит его и отправляет клиенту.
Но проблема в том, что при процессинге формы выполняется ей полная валидация и соответственно мы получает кучу ошибок на каждое незаполненное обязательно поле, которые нам на данном этапе вовсе не нужны. Соответственно вопрос в том, как перестроить форму в обход валидации.
Чтоб было совсем уж наглядно, приведу здесь пример самой типичоной ahah callback функции.
<?php
drupal_process_form($form_id, $form, $form_state);
function ahah_example_select_type_ahah() {
// this part is used to set up $form_state.
// In Drupal 7, these next 11 lines will be put in a core utility function.
// Just remember you'll need them in D6 when you do 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'] = $form_state['post'] = $_POST;
$form['#redirect'] = $form['#programmed'] = FALSE;
$form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
// From here on, we start our own code.
// We just get the element of $form that needs to be refreshed, and just resubmit that
// part through the json call. In this case we want to replace the 'kind' <div> wrapper and it's
// containing select box
$changed_elements = $form['animals_kind'];
unset($changed_elements['#prefix'], $changed_elements['suffix']); // we'll unset the div to make sure it won't be repeated!
// the actual JSON call
$javascript = drupal_add_js(NULL, NULL, 'header');
drupal_json(array(
'status' => TRUE,
'data' => theme('status_messages') . drupal_render($changed_elements), // rebuild just the part that needs to be changed
'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']),
));
}
?>
<?php
function ahah_example_select_type_ahah() {
$first_select = $_POST['first_select'];
if ($first_select) {
$animal_kinds = get_animal_kind($first_select);
$form_element = array(
'animal_kinds' => array(
'#type' => 'select',
'#title' => t('Animal kind'),
'#options' => isset($animal_kinds) ? $animal_kinds : array('First select not choosed'),
'#disabled' => isset($animal_kinds) ? false : true,
),
);
} else {
$form['animal_kinds']['#options'] = array('First select not choosed');
$form['animal_kinds']['#disabled'] = TRUE;
}
drupal_alter('form', $form_element, array(), 'animals_kind_select');
$form_state=array('submitted'=>FALSE);
$form_build_id=$_POST['form_build_id'];
$form=form_get_cache($form_build_id,$form_state);
$form['animal_kinds']=$form_element;
form_set_cache($form_build_id,$form,$form_state);
$form=form_builder($_POST['form_id'],$form,$form_state);
$output = drupal_render($form['animal_kinds']);
drupal_json(array('status' => 'TRUE', 'data' => $output,));
exit();
}
?>
А если так?
чсв повышаем?
2Nikit: простите, был не прав
2Gorr: спасибо! Как раз это решение я и собираюсь использовать (вот отсюда http://drupal.org/node/524220), хоть такой способ и считается «некрасивым», похоже придется на нем остановится.
А почему не красиво? В Вашем случае процесс_форм ведь не нужен. Для poll модуля он обязателен, потому, что там на этом работа формы заканчивается - пользователь отдал голос, больше форма не нужна. Ему показываются результаты предыдущих голосований, к примеру. Поэтому ее там обязательно надо валидировать и сабмитить. А тут вроде нет, или я что-то не учел?
добавить в создавалку форму обработчик полей запроса. баян.
давно на 5ке лепим динамические формы без всяких сторонних библиотек.
В 6-ке ahah вошел в ядро.