Alright, so I have a very very complex form, that also has its own theme function.

The form has 3 different tables, that all need to be replaced based on an AHAH button callback. And so I decided I should just replace the whole form.

What I am obviously doing wrong : I'm literally replacing the whole <form> tag, because there's no way I can have the whole form under one fieldset or wrapper. There's also no way to set a number of "wrappers" to replace, because I want certain areas of the form renewed from the callback but not everything. FYI: The form has multiple multiple buttons, all going to same callback, and I didn't want to create "multiple callbacks" or install a new module like ahah_helper.
The Problem: When you click the button, everything works perfectly the first time. But in firebug you can see a new <form> is created. Then when you submit again right after---now form_token, form_id and form_build_id are GONE. And you see a big empty form, with empty tables.

myform(&$form_state, $formid){
 // ... form code here, just a number of fieldsets, a number of tables, a number of fields outside fieldsets, this is why I didn't use a div
 $form['submitbutton'] = array(
      '#type' => 'submit',
      '#value' => t('Delete Item'),
      '#name' => 'del_my_tabledata',
      '#weight' => 5,
      '#ahah' => array(
        'path' => 'submit',
        'wrapper' => 'myform-form',          
        'progress' => array('type' => 'bar', 'message' => t('Loading...')),
        'effect' => 'fade',
      )
    );
}
myform_theme($form){

  $output = drupal_render($form['results']);
  $output .= drupal_render($form['form_name']);
  // ... Snipped, this code here would be rendering of huge tables.
  $output .= drupal_render($form); // display rest of the form after displayed individual tables and elements. This is for form_token etc.
  
  return $output;
}

function cts_submit_cb(){
  $form = cts_ahah_callback_helper();
  
  // Render the output.
  $output = theme('status_messages'); 
  $output .= theme('myform', $form); // call the theme function to display tables and data.
  
  // Final rendering callback.
  module_invoke_all();
  print drupal_json(array('status' => TRUE, 'data' => $output));
  exit();
}

Comments

executex’s picture

Gonna take a wild guess that no one uses AHAH with their drupal or their complex table-filled forms :P.

jaypan’s picture

I've put together quite a complicated AHAH structure in a form I created, whereby different buttons forced the regeneration of various parts of the form. In the end I wrapped each section in different div tags that were used for replacement, and sometimes the AHAH call regenerates parts of the form that don't actually need to be regenerated for any reason, but had to be in order for all the desired functionality to be present.

Contact me to contract me for D7 -> D10/11 migrations.

executex’s picture

But the thing is I tried AHAH_Helper and it became even worse.

I don't understand why I can't just regenerate the divs I want with appropriate tables.

I have 3 tables in one form. If I make #ahah wrapper as one of the tables, and the user clicks the button, all 3 forms are emptied and regenerated. Why does it delete the values in the table?

I make query calls in my form function to grab data and put it into a $form['table'] array. Then I drupal_render them in theme_my_form() function.

But it seems like it doesn't requery the information. Then it outputs the
tag twice, causing double-submission error (where the form gets blanked out after second submission because form_id, form_token don't get put in $_POST).

Why did Drupal developers not make AHAH simple? Just give me an array of the parent form element that I want to regenerate.
I want to regenerate and retheme $form['business_table'], and all the form elements underneath (including the table rows). How am I suppose to query the table data again?

I am surprised Drupal developers didn't think people would want to use tables with AHAH. It works with upload module, but I can't get it to work myself even though I do practically the same thing. They had to do a lot of code to get it to work, seems very complicated.

jaypan’s picture

I agree, AHAH is a huge headache. It's not easy to use, though once you figure it out it's fairly straightforward.

Apparently they've tried to simplify it for Drupal 7, but I haven't played with it yet.

Anyways, from reading your post, it sounds like maybe the problem is in how you are doing your AHAH. Have you worked with multi-step forms in Drupal? AHAH is essentially the same thing - it's a multistep form. The only difference is that it regenerates the form without a page load.

So your form and the data included should all be in your original for definition. All the AHAH call does is pass the current data (at the point where the AHAH is submitted) to the original form definition, and then regenerates the form data based off that original form definition. So in your original form definition, you have to have if/else (or switch) conditionals, allowing for initial page load, as well as a form definition for when data has been submitted. Then Drupal re-builds the form, and sends back the part you tell to the browser.

I don't know if that makes sense, but if you haven't worked with multi-step forms before, I can point you at a tutorial that will help explain it better, and once you have that down, it should be a lot easier to figure out where your AHAH problem is.

Contact me to contract me for D7 -> D10/11 migrations.

executex’s picture

Tutorial will be nice.

From what I gather you are saying that only OLD information is passed, even if the database has been modified after clicking AHAH button (UPDATE/INSERT) and the form is suppose to have new table data, but does not... right?

So then can someone explain how to load new data in the callback() function, for AHAH, and have it re-printed out.
Say you want to refresh a theme('table') that uses a query to fill in data. How would you make a simple example where the theme table has new data after callback????

Do I use form_state?

jaypan’s picture

Here's the tutorial:

http://drupal.org/node/262422

It gets to multistep forms around step 9 or 10 (though you may have troubles understanding what's going on if you jump straight to there, so I'd suggest doing the whole thing - it doesn't take too long). The principle of the AHAH form declaration is exactly the same as the multistep form declaration - everything is put in the original form declaration, and the form declaration will decide whether it's step/page 1 or step/page 2 (or beyond).

And yes, you are correct in your comments (for the most part). How new data is added is by adding conditionals into your form declaration to deal with both the absence of data (fresh form) and the presence of data (AHAH submitted form, or in the tutorial, just a submitted form).

Contact me to contract me for D7 -> D10/11 migrations.

executex’s picture

So you're saying I should definitely use $form_state['storage'].

in my _form() function, I have a pager_query and tablesort_sql,... It seems like after drupal processes form with AHAH, it doesn't re-query those functions and populate the table again. It just themes the function because I do
$output .= theme('my_form_theme', $form); in the callback.

I'm not understanding how I am suppose to requery the form table. There's not a single example in all of drupal other than upload.module that uses AHAH and tables with table queries. And the upload.module is too complicated and doesn't make any sense either.

rolodmonkey’s picture

You could try the CTools module:

http://drupal.org/project/ctools

It already has functions for creating complex multi-step forms like what you are describing. Unfortunately, the documentation for how to actually do it yourself is still really, really sparse.

--

Read more at iRolo.net

executex’s picture

Yeah, I am not exactly trying to make it multi-step, more like "a ton of forms in one page". Perhaps later I will put in some tabs to make them really exciting.

Currently, the only problem I am encountering is that when you have a theme('table', $data), generated table, the table must be queried again, so I need someone to show example code of where in the AHAH callback I can requery the table and retheme it completely.

I'm thinking it's before drupal_process_form, in the ahah helper function (SEE COMMENTS in code):

 function mymodule_ahah_callback_table($arg) {
  $form_state = array('storage' => NULL, 'submitted' => FALSE);
  $form_build_id = $_POST['form_build_id'];
  $form = form_get_cache($form_build_id, $form_state);
  //$form_state = array('values' => $_POST);
  $args = $form['#parameters'];
  $form_id = array_shift($args);
  $form_state['post'] = $form['#post'] = $_POST;
  $form['#programmed'] = $form['#redirect'] = FALSE;
  drupal_process_form($form_id, $form, $form_state); // I THINK this processes the form via validate() and submit() and that's it.
  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id); /* I THINK it calls the table_form() function again and already requeries everything */
  /* since I have a query in my form function, it should dynamically query again... unfortunately, it just returns an empty table */
  return $form;
}

Basically I want the callback to re-enter the original form and get the NEWER $form values from the array based on the same query.
Perhaps, I need to not use drupal_rebuild_form, perhaps I need to just query again, add it to the $form, and then call form_builder() or something like upload module.

Anyone experienced to figure this out???

My callback looks like this:

function mymodule_submit_table_cb($arg){
  //$form = mymodule_ahah_callback_helper();
  $form = mymodule_ahah_callback_table($arg);
	
  //$results = $form['t'];
  
  // Render the output.
  $output = theme('status_messages'); 
  if($arg == 'table_one'){
    $output .= theme('mymodule_table_one', $form);
  } else if($arg == 'table_two'){    
    $output .= theme('mymodule_table_two', $form);
  } else if($arg == 'table_three'){  
    $output .= theme('mymodule_table_three', $form);
  }
  //$output = 'TESTING: '.$arg;
  
  // Final rendering callback.
  module_invoke_all();
  print drupal_json(array('status' => TRUE, 'data' => $output));
  exit();
} 

I was hoping the callback gets the new $form array by querying the data again... then theme('mymodule_table_one', $form); will be completely NEW data.

executex’s picture

Latest update

IT Seems that there's a better way.
Never replace the <form> tag.

Instead, do this in your form:

$form['#prefix'] = t('<div id="form_wrapper">');
$form['#suffix'] = t('</div>');

Then in your AHAH callback

unset($form['#prefix'], $form['#suffix']);
drupal_render($form);

The only PROBLEM with this method, is that if you have a table in your form, and a theme_your_table() function to render your table properly....
The theme_your_table() function will not launch, unlike when drupal_get_form is called in initial loading that DOES call the theme function thanks to

$form['#theme'] = TRUE;

I think I'm close to solving it.