See http://drupal.org/node/1059694

Steps needed:
1) Create the simplest multi-step form ever.

function a_form($form_state) {
  $num = (int)$form_state['storage']['number'];
  $form['Next'] = array(
    '#type' => 'submit',
    '#value' => $num.'++',
  );
  return $form;
}

function a_form_submit($form, &$form_state) {
  $form_state['storage']['number']++;
}

2) Use the form, hit F5 at any time
3) Form will misbehave from the second submission onwards.

Expected behavior:
F5 (refresh) does not fire the submission handler, does not change the content of the form

Current behavior:
When refreshing on further pages of the multi-step form (after the 2nd submission onwards) the submit-handler is somehow fired changing the content of $form_state. In this example it takes you back to after the 1st submission. In more complex examples you get to a completely different place with no apparent logic. The submit handler is fired with submit buttons never pressed before etc.

Comments

operations’s picture

Same here ! that is incredible .. I can't find a solution for this. Please help !

davidsonjames’s picture

This is the soultion I used. At the top of my form_submit I added:

if(isset($form_state['multistep_values']['form_build_id'])) {
  $form_state['values']['form_build_id'] = $form_state['multistep_values']['form_build_id'];
}

And at the bottom of my form_submit I added:

$form_state['multistep_values']['form_build_id'] = $form_state['values']['form_build_id'];
$form_state['rebuild'] = TRUE;

This seemed to retain the form_build_id even when I refreshed my form mid-way through the stages.

I wrote a post on it here: http://davidsonj.com/blog/how-create-multi-step-form-drupal-7

operations’s picture

Good stuff! I'll try out your code next time I need a multi-step form. For the moment I think its neat.. Thanks

itsmyname’s picture

Status: Active » Reviewed & tested by the community

i have tested the solution from davidson james on drupal 7 - and it works perfect!
thanks james - you saved my day!

Johnny vd Laar’s picture

Version: 6.20 » 7.20

This problem still persists in Drupal 7. The workaround from #2 still works in D7. I didn't check this for Drupal 8.

Johnny vd Laar’s picture

When I look in the function ajax_get_form then I see this:

  // When a form is rebuilt after Ajax processing, its #build_id and #action
  // should not change.
  // @see drupal_rebuild_form()
  $form_state['rebuild_info']['copy']['#build_id'] = TRUE;
  $form_state['rebuild_info']['copy']['#action'] = TRUE;

So when I add this to the top of my _form function then I stay on the same page when I refresh the page. Only issue is that it tries to validate the current step (instead of the previous step which was the one being submitted and thus refreshed).

David_Rothstein’s picture

Version: 7.20 » 8.x-dev
Status: Reviewed & tested by the community » Active
Issue tags: +Needs backport to D7

There is no patch here, so nothing to commit...

Also, I think we should assume this affects Drupal 8 too, unless proven otherwise.

david_garcia’s picture

Issue summary: View changes

Just make sure that before rebuilding, you tell the form API to persist build_id during rebuilds...

Some reverse engineering to get that though, needs some documentation.

$form_state['rebuild_info']['copy']['#build_id'] = TRUE;
$form_state['rebuild'] = TRUE;

david_garcia’s picture

Sorry, that same was said in #6, I just wasted my time.

joachim’s picture

With a multi-step form that doesn't use AJAX, making that change doesn't work: reload the form *advances* it by one step.

The form I'm using is the Migrate Drupal wizard from https://www.drupal.org/project/migrate_d2d

joachim’s picture

I'm seeing this with the the following test code too:

function a_form($form, &$form_state) {
  if (!isset($form_state['storage']['number'])) {
    $form_state['storage']['number'] = 1;
  }
  
  $num = (int) $form_state['storage']['number'];
  $form['Next'] = array(
    '#type' => 'submit',
    '#value' => $num . '++',
  );
  return $form;
}

function a_form_submit($form, &$form_state) {
  $form_state['rebuild'] = TRUE;
  $form_state['storage']['number']++;
}
david_garcia’s picture

@joachim: The problem is that you are storing step data server-side. There might be another approach in wich you detect the real step by the means of the element triggering the submit.

BTW, in D7 there is no need to use $form_state['storage'], you can use any key in $form_state.

Try storing step information in a hidden field:

if (!isset($form_state['input']['stage'])) {
$form_state['input']['stage'] = 1;
}

$form['stage'] = array(
'#type' => 'hidden',
'#value' => $form_state['input']['stage'],
);

joachim’s picture

> The problem is that you are storing step data server-side

Yes, since posting my comment, I've concluded the same thing.

Basically, there are two possibilities:

1. drupal_rebuild_form() keeps the old build ID. The re-sending of POST data by the browser means that the submit handler causes the form to go from the current step in the cached version to one step further: the user sees the form advance to current step + 1.
2. drupal_rebuild_form() makes a new form ID. The re-sending of POST data by the browser means that the submit handler causes the form to go from the first step to the second step: the user sees the form go back to step 2.

I don't see that there's a way for FormAPI to fix this: as you say, the client-side form needs to know what step it is currently on.

david_garcia’s picture

One last finding: if you have a step in you multistep that does not have a submit button (for example a last step with a message) when the user refreshes (F5) on that last step form_state is lost and form completely rebuilt, because in the last build the server does not acknowledge the existance of a submit button and will not process the submit handler.

To overcome this, just make sure than on every form build you have at least 1 submit element.

I added a hidden one to every form build:

  $form['multistepsubmit'] = array(
                                     '#prefix' => '<div style="display:none;">',
                                     '#sufix' => '</div>',
                                     '#type' => 'submit',
                                 );
joachim’s picture

I've had a look at the form wizard in Examples module, to see how that works.

It *doesn't* use a hidden value -- but behaves correctly when any step is reloaded! What does it do differently?

joachim’s picture

Category: Bug report » Support request
Issue tags: -Needs backport to D7

The crucial code is this in the submit handler for the next step:

    if (!empty($form_state['step_information'][$current_step]['stored_values'])) {
      $form_state['values'] = $form_state['step_information'][$current_step]['stored_values'];
    }

I've filed #2370763: clarify how the form wizard deals with page reload on the Examples project.

Changing this to a support request, as Examples demonstrates that there's no bug in core.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Coyote6GraphX’s picture

I know this is old, but for others with the same issue on Drupal 7, I have a multi step form using ctools that I needed to save $form_state data to the session for, but needed a step to repeat as much as needed during the process. I was running into the same issue on page refreshes and couldn't get the other suggestions to work for my case, so this is my work around.

EDIT:
Removed old solution that turned out to only be sporadically working.

SOLUTION:
Used drupal_goto ('page/my/form/is/on') to redirect at the end of the _submit function to reload the page without the $_POST data and therefore, preventing _submit from firing upon page reload.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev
cilefen’s picture

Status: Active » Closed (outdated)

I am closing this support request because there have been no recent comments.

The Drupal Core issue queue is not the ideal place for support requests. Consider other sources of support.