Sitecore Experience Forms are new to Sitecore 9. This module is a built-from-the-ground-up replacement for the old Web Forms for Marketers and it’s pretty powerful. One of its features is multi-page forms. Multi-page forms means you can segment your form via next and previous buttons. One thing that isn’t really clear is how to pass data from one page to another.
I wanted to figure out how to pass data across pages. Here’s the scenario:
- Page 1 has a “First Name” single-line input field
- Page 1 has a “next” button
- Clicking the “next” button brings the user to Page 2
- Page 2 has a header (text field) that says “Thanks,
{{First Name}}
”
It doesn’t seem like there was an easy way to get this information. I posed the question on Stack Exchange but nobody seemed to have an answer, so I became determined to figure this out myself.
After doing some reflection with dotPeek, I was able to determine that view models all go through the <forms.getModel>
pipeline. I explored a few other options, including overriding the FormBuilderController
, but determined this pipeline was the cleanest way to go. Going this route, I created a pipeline processor that determines if the passed in model was a TextViewModel, which is the type used on Text fields. If it is, the processor will replace instances of {{First Name}}
with the value grabbed from the First Name input field on page 1.
Let’s take a look at some code:
public class ReplaceFirstNameToken : MvcPipelineProcessor<GetModelEventArgs>
{
private readonly IFormRenderingContext _formRenderingContext;
/// <summary>
/// ID of the Field on the Form
/// </summary>
public string FieldId { get; set; }
public ReplaceFirstNameToken(IFormRenderingContext renderingContext)
{
_formRenderingContext = renderingContext;
}
public override void Process(GetModelEventArgs args)
{
// Check to make sure the Field ID has been set
if (string.IsNullOrEmpty(FieldId))
{
Log.Error("ReplaceFirstNameToken: Parameter cannot be null or empty: FieldId", this);
return;
}
// This token replacement is only valid on form fields that inherit from TextViewModel (e.g. the "Text" field type)
if (!(args.ViewModel is TextViewModel textViewModel)) return;
ReplaceTokensIfApplicable(textViewModel);
}
protected virtual void ReplaceTokensIfApplicable(TextViewModel textViewModel)
{
// If the FieldID isn't a valid ID, don't do anything
if (!ID.TryParse(FieldId, out ID fieldId)) return;
// Get the value of the first name field
var textField = _formRenderingContext.GetPostedField(fieldId) as StringInputViewModel;
string firstName = textField == null ? string.Empty : textField.Value;
// Replace the FirstName token in the Text of the textViewModel
textViewModel.Text = textViewModel.Text.Replace("{{FirstName}}", firstName);
}
}
And the corresponding config patch:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<forms.getModel>
<processor type="MyProject.Foundation.Form.Pipelines.Forms.GetModel.ReplaceFirstNameToken, MyProject.Foundation.Form" patch:after="processor[@type='Sitecore.ExperienceForms.Mvc.Pipelines.GetModel.CreateModel, Sitecore.ExperienceForms.Mvc']" resolve="true">
<!-- The ID of the Input field itself on the form -->
<FieldId>{10F6D000-C0B9-4053-9039-D97778D1E1C8}</FieldId>
</processor>
</forms.getModel>
</pipelines>
</sitecore>
</configuration>
Voila! I have now signed up for the mailing list to be notified when I can become Akshay’s friend!