Add links to the step indicator

Created on 21 October 2020, about 4 years ago
Updated 29 July 2023, over 1 year ago

Problem/Motivation

When creating forms with a lot of steps, it would be useful to have links on the step indicator that allows the user to easily go to another part of the form.

Proposed resolution

We did something like this in a form alter hook:

/**
 * @param $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 */
function _foo_change_step(&$form, FormStateInterface $form_state) {
  /** @var \Drupal\simple_multistep\MultistepController $multiStep */
  $multiStep = $form_state->get('multistep_controller');
  $multiStep->setFormState($form_state);
  $multiStep->saveInputValues();
  $multiStep->saveStoredValues();

  $trigger = $form_state->getTriggeringElement();

  $currentStep = $multiStep->getCurrentStep();
  $targetStep = $trigger['#parents'][0];

  if ($targetStep > $currentStep) {
    for ($i = $currentStep; $i < $targetStep; $i++) {
      $multiStep->increaseStep();
    }
  }
  elseif ($targetStep < $currentStep) {
    for ($i = $currentStep; $i > $targetStep; $i--) {
      $multiStep->reduceStep();
    }
  }

  $stored_input = $multiStep->getInputValues();
  if (isset($stored_input[$targetStep]) && !empty($stored_input[$targetStep])) {
    $form_state->setUserInput($stored_input[$targetStep]);
  }

  $form_state->set('multistep_controller', $multiStep);
  $form_state->setRebuild();
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * @link https://www.drupal.org/project/simple_multistep/issues/2993675#comment-13069202
 * @see simple_multistep_form_alter()
 */
function foo_form_alter(&$form, FormStateInterface $form_state) {
  /** @var \Drupal\simple_multistep\MultistepController $multiStep */
  if ($multiStep = $form_state->get('multistep_controller')) {
    $currentStep = $multiStep->getCurrentStep();
  }
  else {
    $currentStep = 0;
  }
  $indicator = new StepIndicator($form, $form_state, 0);

  $form['steps_label'] = [
    '#type' => 'container',
    '#weight' => -1,
  ];
  foreach ($indicator->getSteps() as $step_number => $step) {
    $format_settings = $step->format_settings;
    if ($format_settings['show_step_title']) {
      $button = [
        '#type' => 'button',
        '#value' => $step->label,
        '#validate' => ['_foo_change_step'],
      ];
      if ($currentStep == $step_number) {
        $button['#disabled'] = TRUE;
        $button['#attributes']['class'][] = 'active';
      }

      $form['steps_label'][] = $button;
    }
  }
}

(The fact that FormStep::setCurrentStep() is protected forced us to do some weird loops.)

✨ Feature request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡«πŸ‡·France prudloff Lille

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024