3 дня с #AHAH

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

Аватар пользователя Stutzer Stutzer 26 сентября 2009 в 8:50

Чертов друпаловский #AHAH! У меня сейчас мозг взорвется!
Это какой–то п#$@!ц!

Извините. Спасибо. Пожалуйста.

Комментарии

Аватар пользователя Stutzer Stutzer 26 сентября 2009 в 9:19

Я довольно редко читаю что-то на русском. Чаще хэндбук и ишью трэкер на d org ну и в исходниках роюсь, разумеется. Однако, подходящих исходников пока не нашел.
Вобще, я пытаюсь сделать пару селектов, один из которых зависит от другого а-ля Страна —> Город (наираспространеннейшая задача)
И на текущий момент у меня остался один вопрос: как перестроить форму в функции ahah callback в обход валидации всех полей.

Аватар пользователя Stutzer Stutzer 26 сентября 2009 в 9:48

Думаю, если бы вы были в теме, фразы «перестроить форму в обход валидации всех полей» было бы более чем достаточно )
В общем-то это не пост-вопрос, это скорее крик души — нужно было как-то разрядиться ))

Но если в кратце, то проблема в следующем.

Задача: сделать зависимый селект без перезагрузки формы (а-ля 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'];
  
  
$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;

  

drupal_process_form($form_id$form$form_state);
  
  
$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(NULLNULL'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']),
  ));
}
?>
Аватар пользователя gorr gorr 26 сентября 2009 в 10:57

<?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();
}
?>
А если так?

Аватар пользователя Stutzer Stutzer 26 сентября 2009 в 11:13

2Nikit: простите, был не прав Wink
2Gorr: спасибо! Как раз это решение я и собираюсь использовать (вот отсюда http://drupal.org/node/524220), хоть такой способ и считается «некрасивым», похоже придется на нем остановится.

Аватар пользователя gorr gorr 26 сентября 2009 в 12:01

А почему не красиво? В Вашем случае процесс_форм ведь не нужен. Для poll модуля он обязателен, потому, что там на этом работа формы заканчивается - пользователь отдал голос, больше форма не нужна. Ему показываются результаты предыдущих голосований, к примеру. Поэтому ее там обязательно надо валидировать и сабмитить. А тут вроде нет, или я что-то не учел?

Аватар пользователя Ильич Рамирес Санчес Ильич Рамирес Санчес 26 сентября 2009 в 13:03

"Stutzer" wrote:
И на текущий момент у меня остался один вопрос: как перестроить форму в функции ahah callback в обход валидации всех полей.

добавить в создавалку форму обработчик полей запроса. баян.
давно на 5ке лепим динамические формы без всяких сторонних библиотек. Smile