Today, I was working with drupal 6's AHAH form elements. Initially, I was delighted at how well they worked. That delight turned to confusion once I realized that the form elements I had put in the menu callback of the #ahah['path'] was missing its name attribute. After doing a bit of research in how the poll module handled the formapi voodoo, I created a generalized function to aid in building AHAH callbacks. If there is a better way to do this, I wasn't able to find it.
<?php
// this is an example menu_callback that would be referenced by the #ahah['path'] property
function easy_ahah_form_field() {
// all you have to worry about is the new form field that will be inserted via #ahah
$form = array(
'#type' => 'select',
'#title' => 'You selected that because...',
'#options' => array(
'1' => 'drugs',
'2' => 'I do what I want.',
'3' => "I'm feeling lucky..."
),
);
// ahah_render is where the magic happens.
// 'the value of this field will show up as $form_value['user_problem']
$output = ahah_render($form, 'user_problem');
print drupal_to_js(array('data' => $output, 'status' => true));
exit();
}
/*
This function is largely based on the poll module, its been simplified for reuse.
$fields is the specific form elements you want to attach via ahah,
$name is the form fields array key... e.g. the name for $form['title'] is "title"
*/
function ahah_render($fields, $name) {
$form_state = array('submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
// Add the new element to the stored form. Without adding the element to the
// form, Drupal is not aware of this new elements existence and will not
// process it. We retreive the cached form, add the element, and resave.
$form = form_get_cache($form_build_id, $form_state);
$form[$name] = $fields;
form_set_cache($form_build_id, $form, $form_state);
$form += array(
'#post' => $_POST,
'#programmed' => FALSE,
);
// Rebuild the form.
$form = form_builder($_POST['form_id'], $form, $form_state);
// Render the new output.
$new_form = $form[$name];
return drupal_render($new_form);
}
?>
Comments
Maybe I'm missing something...
OK, maybe I'm missing something, but when I use this code it replaces my existing form with the new select element, rather than appending the new element to the form. Can anyone suggest what am I doing wrong? My code is based heavily off the poll module, as well. Many thanx for the help, Ben
Be sure to set your
Be sure to set your $form['#ahah']['wrapper'] to the css ID you wish to replace.
thanks
i'm not sure if i got it quite right, but if so thanks for the post. it might be quite useful.
Thank you very much!
I've been similarly elated and then disappointed/confused by AHAH fields in D6. This may help enormously.
Is there something similar,
Is there something similar, but for drupal 5 ?!
No. And don't quote me on
No. And don't quote me on this, but I think the formapi needed to be tweaked in 6 to allow AHAH to work too. So backporting it to 5 is probably not practical.
Could be improved in D7
This is certainly something I want to get improved before D7 rolls out. For one, I want to eliminate the #ahah['path'] property and put in a #ahah['callback'], where you can call a function directly without making a menu callback. Second, there *really* needs to be an easier way to render just a portion of a form. Even though the JavaScript side of things is really easy, we need better support on the FormsAPI side to render a small piece of the form.
Thanks for putting together this small example, hopefully it won't be needed forever. :)
Impractical
You need a menu callback at some point along the line - whether or not this menu callback is a single one implemented by the Form API and invisible to your module. As long as you have to go through the menu system, you might as well do it directly...