I have been working on something of a wizard.module for Drupal 5.1. In so doing, I've got code that draws a form with "Next" and "Back" buttons. I've got the basic functionality for the wizard to understand when a user wants to move to the next "step" or go back to the previous step.

The problem I have found seems to be restricted to the "checkbox" form type. When returning to a previously viewed form, FAPI seems to override the #default_value for checkboxes, and attempts to insert values that have been POSTed. It overwrites #default_value even if no data is posted.

I have attached a test case module which demonstrates the problem.

Essentially the flow is this:

Page 1 (fresh):
- Display a checkbox. Check it.

...Press "next" to submit form (save the form values)...

Page 2 (resulting from page 1 submit)
- do something

...Press "back" to submit form and return to page 1. Set defaults for page 1 form elements based on saved form information.

Page 1 (resulting from page 2 submit)
- Checkbox is unset, even if #default_value is set to 1

This basic flow occurs regardless of how the page 1 form is initially constructed. Even putting a hard coded #default_value => 1 in the checkbox definition is overridden. The only way to workaround this problem is to have a hidden field on step 2, so submitting back to step 1 has the value set in $_POST/$form_values.

Once again: This problem only appears to occur on "checkbox" form elements (I haven't actually tried "checkboxes", but have tried textfield, textarea and radios, all of which work fine).

Comments

coofercat’s picture

Status: Needs review » Postponed (maintainer needs more info)

Sorry, adjusted because I haven't actually submitted a patch! ;-)

pielgrzym’s picture

Hi,

I had a similar problem (the 'checkboxes' field is even worse. Is seems totally useless). Mine multipage monstrosity used drupal cache to store each step's values. The only way to set the checkboxes 'on' is to pass them:

'#attributes' => array('checked' => 'checked');

I made a function that retrieved the checkbox value from drupal cache and returned the proper array if value was non 0:

function prev_step_chkbox($step, $var1) {
	$cache_name = 'myModule-'.session_id().'-'.$step;
	$cache_get = cache_get($cache_name, 'cache');
	$r_values = unserialize($cache_get->data);
	//Example: $form = $r_values['name'];
	if ($r_values[$var1]) {
		return array('checked' => 'checked');
	}
	else {
		return;
	}
}

// Later on in the form:

$form['bunch_of_boxes'][some_checkbox'] = array(
			'#type' => 'checkbox',
			'#title' => t('Pokazy mody'),
			'#default_value' => FALSE,
			'#attributes' => prev_step_chkbox($step, 'moda'),
		);

Hope I helped :)

coofercat’s picture

Thanks for confirming my findinging (and expanding this bug into "checkboxes" and not just "checkbox" form types!).

Actually, I found a way to "hack" a workaround that happens to work in my scenario quite well: I have a recursive function that runs through a $form structure setting #default_value as required. As it does so, it checks if what it's setting is a checkbox, in which case it also sets $_POST[whatever] (which would have been unset). I've found this seems to work nicely, although it is of course an utter hack. Using attributes as you suggest is also a bit nasty, but possibly a better way to do the same thing.

pielgrzym’s picture

Would you be so kind to paste code for this function? I've tried that and it did't seem to work (I don't quite remember if I used it with single checkbox fields or with much more problematic checkboxes field).

Actually the whole multipage form is one big hack ;) hopefully the new fapi will fix those issues :)

coofercat’s picture

StatusFileSize
new1.83 KB

Function attached, although I'm not sure how useful it'll be to you (I guess it's got the basic layout you'll need). I'll warn you, it's not optimised particularly well, I'm sure there are better ways to do what it does.

Multipage forms a bigh hack? That's harsh! I actually think they're quite neat, although you can see thier heritage. As I say, I'm working on wizard.module which (I think) makes wizards considerably easier to use, although by their very nature, there's always going to be complexity. I'll post a link once it's ready...

coofercat’s picture

StatusFileSize
new20 KB

A bit of good news! This is fixed in Drupal 6 - yay!

That said, it's not entirely consistent. 'checkbox' elements are handled completely automatically, but 'checkboxes' require #default_value to be set correctly each time the form is displayed. Not too big a deal, but weird that 'checkboxes' should be different (now) from every other form element type.

I've attached a Drupal 6 testcase if anyone wants to prove it to themselves. Bending it into shape to work on Drupal 6 was pretty tough going, so it's a bit of a mess. Still, proves a point.

I'm sure Drupal 5'ers would like to see some sort of patch to make it work there, but all I've got is workarounds.

Island Usurper’s picture

I think I got lucky in that my checkboxes were on the last page of the form, so at least the data gets saved. I'd still like to get the default values to show up at the right time, though....

Island Usurper’s picture

Status: Postponed (maintainer needs more info) » Active

I think the intent of active(needs more info) is to get the issue submitter to bring more info, not as a request for more info.

Setting to active to get it to show up on the issue queue.

greenmachine’s picture

Priority: Normal » Critical

In my opinion, this is a critical bug with the FAPI's handling of multi-step forms.

I believe I have this problem also: if I directly call the form through drupal_get_form with a $form_values variable that sets the form to the step with checkboxes, the defaults are set correctly. If I get to that step (with the checkboxes) by walking through the form, the defaults are not set.

Checkboxes defaults are set fine on the first page of the form, not following pages.

Ouch, hours of banging head against desk on this ... I am not sure where to begin looking in core Drupal code to figure this out and think about a patch.

stella’s picture

subscribing

fonant’s picture

This is annoying me too... everything other than checkbox/checkboxes honours the #default value, but these two types don't.

Seem to have a useable workaround, setting $_POST['formelement'] to the required default value if $_POST['formelement'] isn't set. Thus if the element is being submitted, $_POST['formelement'] is processed as normal, but if we're building the form having come from another step, $_POST['formelement'] is set to the saved value.

For example, using an input checkboxes widget called "options", and getting the default from the session variable with the same name:

        //----- hack to work around defaults bug in Drupal 5.1 -----
        if (!isset($_POST['options'])) {
            $_POST['options'] = $_SESSION['options'];
        }
        //----- to here -----
         $form['options'] = array(
        '#type' => 'checkboxes',
        '#title' => 'Options',
        '#options' => array('Option 1','Option 2','Option 3'),
        '#default_value' => $_SESSION['options'],
        );

Hope this helps someone else.

fonant’s picture

Actually, the code above doesn't quite work for multi-step forms, as you can't de-select all the checkboxes at once (in that case $_POST['options'] should be empty).

An improved hack is this:

...
// code here to increment/decrement $step for our multi-part form
...
// Only copy saved values into $_POST if we're coming from the previous or next page
if ($_POST['step'] != $step) $_POST['options'] = $_SESSION['options'];
drumm’s picture

Status: Active » Closed (won't fix)

Please re-open if this is confirmed on the current version of Drupal 5, currently 5.16.