Output all form steps

Just placing this here for reference…

If you need to output all the steps in your multi-step formalicious form, so that you can:

  • Visually show what steps a user has to fill out
  • Show which step the user is currently on
  • Show which steps have been completed

Example:

The user is on step 2 after completing step 1:

Create a snippet called getFormSteps and place the following code inside it:

<?php
/**
 * getFromSteps v.1.0
 * An unoffical utility snippet for Formalicious by Sterc
 * 
 * This utility snippet outputs all the steps for a multistep form
 * based on a given form ID
 * 
 * Usage:
 * Put the snippet in your &stepTpl and call the snippet like this:
 * [[!getFormSteps? stepFormId=`[[!+form_id]]` &tpl=`myFormStepsTpl`]]
 * 
 * Useful placeholders for the snippet tpl are:
 * [[+currentStep]]
 * [[+title]]
 * [[+rank]]
 *
 */

// get the id of the form
$stepFormId = $modx->getOption("stepFormId", $scriptProperties);

// if there is no form id, stop here...
if (empty($stepsFormId)) {
    return;
} else {
    // get related steps
    $output = array();
    $getFormSteps = $modx->query("SELECT * FROM `modx_formalicious_steps` WHERE `form_id` ='" . $stepsFormId . "'");

    if ($getFormSteps) {
        while ($row = $getFormSteps->fetch(PDO::FETCH_ASSOC)) {
            $placeholders = array_merge($scriptProperties, $row);
            if (!empty($tpl)) {
                // if a tpl is defined in the snippet call, get placeholders
                $output[] = $modx->getChunk($tpl, $placeholders);
            } else {
                // if no tpl is defined in the snippet call, output an array
                $output[] = "<pre>" . print_r($placeholders, true) . "</pre>";
            }
        }
    }
    
    return implode("\n", $output);
}

In stepTpl add the following example markup somewhere in your template:

<div class="c-stepprocess">
    <ol class="c-stepprocess__items">
        [[!getFormSteps? &stepsFormId=`[[!+form_id]]` &tpl=`tpl_getformsteps_row`]]
    </ol>
</div>

Create a chunk called tpl_getformsteps_row (this is referenced in the snippet above):

<li class="c-stepprocess__item [[+rank:add=`1`:eq=`[[+currentStep]]`:then=`c-stepprocess__item--active`:else=``]] [[+rank:add=`1`:lt=`[[+currentStep]]`:then=`c-stepprocess__item--complete`:else=``]]"><span>[[+title]]</span></li>

Then with a bit of css styling (in particular, using css counter-increment), you can create something like the example image shown above.

Hi,
This is exactly what i want to achieve so thanks for posting.
However i can’t get it to work and wonder if you (or anyone else could help).
The form doesn’t display when your code is executed but the new html is present.
This is the html generated:
< form action=“test2.html?step=1” method=“POST” enctype=“multipart/form-data” novalidate="">
< div class=“c-stepprocess”>
< ol class=“c-stepprocess__items”>
</ ol>
</ div>
< input name=“submit-form5” value=“Next” type=“submit”>
</ form>

Thanks for any help

Janice

Hi Janice - what version of Formalicious are you using?

Something changed in an update a while back. I’ll look through my code and report back shortly.

@9thwave - I can’t edit my original post, but since the last Formalicious update (1.4.4-pl) there is a new final step that is required to get this working, plus a slight template change to step 2.

The complete steps are:

  1. Create a snippet called getFormSteps and put this inside it:
<?php
/**
 * getFromSteps v.1.0
 * An unoffical utility snippet for Formalicious by Sterc
 * 
 * This utility snippet outputs all the steps for a multistep form
 * based on a given form ID
 *
 */

// get the id of the form
$stepFormId = $modx->getOption("stepFormId", $scriptProperties);

// if there is no form id, stop here...
if (empty($stepsFormId)) {
    return;
} else {
    // get related steps
    $output = array();
    $getFormSteps = $modx->query("SELECT * FROM `modx_formalicious_steps` WHERE `form_id` ='" . $stepsFormId . "'");

    if ($getFormSteps) {
        while ($row = $getFormSteps->fetch(PDO::FETCH_ASSOC)) {
            $placeholders = array_merge($scriptProperties, $row);
            if (!empty($tpl)) {
                // if a tpl is defined in the snippet call, get placeholders
                $output[] = $modx->getChunk($tpl, $placeholders);
            } else {
                // if no tpl is defined in the snippet call, output an array
                $output[] = "<pre>" . print_r($placeholders, true) . "</pre>";
            }
        }
    }
    
    return implode("\n", $output);
}
  1. Create a chunk called stepTpl and put this inside:
<legend class="c-form__legend">[[!+title]]</legend>
<div class="c-stepprocess">
    <ol class="c-stepprocess__items">
        [[!getFormSteps? &stepsFormId=`[[!+form_id]]` &tpl=`tpl_getformsteps_row`]]
    </ol>
</div>
<div class="c-form__groups">
[[!+fields]]
</div>
  1. Create a chunk called tpl_getformsteps_row (this is referenced in the snippet above):
<li class="c-stepprocess__item [[+rank:add=`1`:eq=`[[+currentStep]]`:then=`c-stepprocess__item--active`:else=``]] [[+rank:add=`1`:lt=`[[+currentStep]]`:then=`c-stepprocess__item--complete`:else=``]]"><span>[[+title]]</span></li>
  1. Where you call the Formalicious renderForm snippet, add the &formTpl parameter using stepTpl as the value. For example:
<div class="c-form">
[[!renderForm? 
    &form=`form_id_goes_here`
    &formTpl=`stepTpl`
]]
</div>

Let me know if that works for you!

P.S - Feel free to change the html markup

Thanks for that.
It’s getting close. The steps are now displaying but not clickable.
The generated HTML looks like this:

< div class="c-stepprocess">
< ol class="c-stepprocess__items">
    < li class="c-stepprocess__item  c-stepprocess__item--complete">< span>Step 1< /span>< /li>
 < li class="c-stepprocess__item  c-stepprocess__item--complete">< span>Step 2< /span>< /li>
< li class="c-stepprocess__item  c-stepprocess__item--complete">< span>Step 3< /span>< /li>
< ol>

< /div>

I am calling the form from the resource content area like this:

< div class="c-form">[[!renderForm? &form=`5` &formTpl=`stepTpl`]]</div>
[[$forms]]

Where [[$forms]] is:

[[!renderForm? &form=`[[!*formalicious]]`]]

I’m not sure you need the forms chunk, because you are effectively rendering the form twice?

Perhaps something like this would work better:

[[!renderForm? &form=`[[!*formalicious]]` &formTpl=`stepTpl` ]]

Yes, the steps are not clickable - I built it this way to funnel the end user to completion rather than clicking back and forth.

Having said that, i’m sure it’s possible by modifying tpl_getformsteps_row

I tried that call in the resource content area and as a chunk and i get a blank page with the following html. It only displays as expected on the front end when i use two calls. but the steps are then not rendering as expected;

< div class="c-form">
  < legend class="c-form__legend">< /legend>
< div class="c-stepprocess">
    < ol class="c-stepprocess__items">
    < /ol>
< /div>
< div class="c-form__groups">
< /div>

< /div>

I’ll keep trying to see if i can suss what’s happening.

Re steps - yes of course. I can style them as necessary.

Thanks for your help so far.