AHAH Example: Select control and generated checkboxes

Note that this is currently maintained in the Examples project so the code here may not be the latest.

In this example we use a select control to determine how many checkboxes are generated.

(Experience this one at http://d6.drupalexamples.info/examples/ahah_example/autocheckboxes.)

/**
* @file
* A Self-configure a form based on a select control
* Add the number of checkboxes specified in the select
*/
function ahah_demo_autocheckboxes(&$form_state) {

$default = !empty($form_state['values']['howmany']) ? $form_state['values']['howmany'] : 1;
$form['howmany'] = array(
'#title' => t('How many checkboxes do you want?'),
'#type' => 'select',
'#options' => array(1=>1, 2=>2, 3=>3, 4=>4),
'#default_value' => $default,
'#ahah' => array(
'path' => 'ahah_demo/autocheckboxes/callback',
'wrapper' => 'checkboxes',
'effect' => 'fade',
),

);

$form['checkboxes'] = array(
'#title' => t("Generated Checkboxes"),
'#prefix' => '

',
'#suffix' => '

',
'#type' => 'fieldset',
'#description' => t('This is where we get automatically generated checkboxes'),
);

$num_checkboxes = !empty($form_state['values']['howmany']) ? $form_state['values']['howmany'] : 1;
for ($i=1; $i<=$num_checkboxes; $i++) {
$form['checkboxes']["checkbox$i"] = array(
'#type' => 'checkbox',
'#title' => "Checkbox $i",
);
}

$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Click Me'),
);

return $form;
}

/**
* Callback for autocheckboxes. Process the form with the number of checkboxes
* we want to provide
*/
function ahah_demo_autocheckboxes_callback() {
$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_state['post'] = $form['#post'] = $_POST;
$form['#programmed'] = $form['#redirect'] = FALSE;

// HACK: Select values changing never get recognized
unset ($form['howmany']['#value']);

drupal_process_form($form_id, $form, $form_state);
$form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);

$checkboxes = $form['checkboxes'];
$output = drupal_render($checkboxes);

// Final rendering callback.
print drupal_json(array('status' => TRUE, 'data' => $output));
exit();
}
?>

AHAH Notes and Issues

Gotchas to watch out for

  • The callback must emit the JSON and nothing else. If it emits anything else, the JSON won't be parsed, and all will fail. How can it emit anything else, you ask? Well, if Devel module is turned on and it's timing pages and putting that at the bottom of the page, you're sunk. If Devel module is outputting errors to the screen, you're sunk. If you're debugging and you accidentally do a var_dump. nothing will work.
  • When you create a new callback, hit it with the web browser. If it's not working yet, hit admin/build/modules to rebuild the menu system's cache.
  • In a complicated form with textareas, you will probably want to set '#TREE' => TRUE for the form. If you have elements with the same name in different fieldsets, AHAH will be unable to get the correct #ahah information for the element you've clicked, unless it's the first one with this name. If you use #TREE, the browser will submit a full-qualified name for the changed element, which AHAH can use correctly.

Other Notes

  • You can replace any section of the form (or probably of the page). In my examples, I replaced only a particular region of the form (marked off by #prefix and #postfix in the form definition). You could replace the whole form, or something completely different on the page. Probably performance is best if you replace the smallest region possible.

Drupal Debugging

Debugging Drupal is not that much different from any kind of debugging or problem-solving, and the topics we'll cover are the same regardless of your level of Drupal or PHP expertise.

Here we'll cover three topics:

  1. Strategy: How do we think about the problem? How do we gather basic information about the problem? How do we not get stuck debugging the wrong problem?
  2. Tools: What tools can be bring to bear on our problem? What should we have prepared in advance?
  3. Techniques: What specific techniques can we use?

Although you may be here for #3, the first two will probably have more of an impact on your success, so we're going to spend some good time on them first.

Debugging Strategies

Turn on your brain first

Before beginning a debugging effort, turn on your brain. Ask yourself some questions:

  • Have you looked at the Drupal log yet? Going to admin->reports->dblog has solved many a problem... after I've spent an hour trying to figure it out.
  • Have you looked at the Apache log yet? If you're debugging a WSOD (White Screen of Death) and haven't looked at the Apache log yet, you're wasting your time. If you don't yet know where the apache log is on sites you maintain, find out now.
  • Has anything changed on the site lately?
  • Is your internet connection working?
  • Are other sites on the same server working correctly?
  • Does the dev or staging version of your site still work?

Divide and Conquer: Binary Search

Almost any piece of software or any debugging problem is too large to understand all at once. So you have to figure out ways to divide the problem. If you can divide the problem in half a couple of times you'll rapidly have a more understandable problem.

There are many ways to divide up a problem:

  • Divide it into different sections of code
  • Divide it into different modules or different combinations of modules
  • Divide it into different versions (if it appears to be a version-related issue)

Best practices that will make problem-solving easier

Many of the items in this tutorial may require you to learn a new technique or two. Commit to breaking out of the stalemate. Don't let skills that you haven't yet mastered keep you from really resolving a problem. Learn them, even if it means investing in them in the midst of a crisis. Never let a mysterious site remain mysterious. Commit the resources you need to shine the light on your Drupal installation. It's worth it - it will pay off in no time.

  1. Keep a log of changes on the site. Note when a new module is installed, when a patch is applied, when an upgrade is done. You may want to consider using the journal module to help with this.  But a simple log like this one can make problemsolving easier.
  2. Keep your code under source control, and know how to use it.
  3. Keep multiple backups of your database. Use the Backup and Migrate module for small sites, or another backup technique for larger sites.
  4. Make sure you have an environment set up that is similar to your production environment where you can set up a clone of the production site at a moment's notice.
  5. Use a notebook to record changes as you make them when you're working through a lot of experiments, like enabling and disabling modules. Otherwise you may not be able to remember where you came from or how to get back there.

Debugging Tools: Preparation and Investment Ahead of Time

If you invest in your infrastructure ahead of time, life will be so much easier. If you know how to load and dump the database quickly and how to get a file copy of a production database in moments, and you know how to revert to an earlier version of the code, life will be so much better. Learn how to do these things, whether you do "code" or not:

  1. Have an environment where you can run a copy of any production website you're responsible for. This doesn't mean the exact same setup - it may not even need to be the same operating system. But you'll probably want to match PHP major versions and Mysql major versions. If you have PHP 5.2 and Mysql 5 on the production server, you'll probably need an environment that comes close to that. Yes, if your production site runs Linux, you'll probably want to be able to duplicate that. But many problems and issues can be demonstrated successfully on a Windows machine with Xampp or a Mac with Mamp. And most Drupal websites will run fine in many environments.
  2. Learn how to clone your production website in moments. When a crisis time comes for your production website, you need to be able to make a copy of it to work with it. Trying to debug on a live site has enormous disadvantages: Your own conservatism about making changes is one of those, the risk that you'll break something worse is another, and just the fact that it's far away and harder to work with is a third. Working on a cloned website is non-negotiable, in my opinion, and will pay off at least 90% of the time.
    Demonstration: Cloning a website in moments
  3. Keep your site under source control and know how to use it. If your site is under source control, you can roll back any part of it in moments and you can experiment easily with different versions of the code.
    Demonstration: Using source control to debug. (Delete a section. Delete modules. Revert to an earlier time. Move forward in time)
  4. Learn Drush. You'll be happy you did.
  5. Get Step-debugging going if you can work with PHP code. You really can't live without it.
    Demonstration: Step debugging with Eclipse.

Pages

Where to find me

Email me, randy at randyfay.com, Find me on ddev.com, Drupal.org and Slack: rfay, Facebook: randyfay, Hobobiker.com: The story of our 2 1/2 year bike trip.

Updated 2025-12-03