5

I have a multi-page form built in Sitecore Experience Forms on Sitecore 9.0.1.

On the first page, there is a "First Name" field.

On the second page, we would like to display the text "Thank you, [First Name]".

Is there any way to do this in Sitecore Experience Forms?

Thanks

3

I was able to get this to work using a custom pipeline processor:

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 configs:

<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>

Now, {{FirstName}} in Text fields will get automatically replaced with the value of the input of the First Name input field

I've detailed this out further in my blog post

|improve this answer|||||
  • Ben, link only answers would not help if for any reason the linked page is not accessible. Would you mind posting a self explanatory answer for future searches along with the link? – Amitabh Vyas Aug 10 '18 at 13:44
  • @AmitabhVyas fair enough. I'll update the answer – Ben Lipson Aug 10 '18 at 13:46
0

Using your answer as inspiration I expanded upon it by creating a custom submit action that would store all the form values in the session and then a custom form element that would be placed after the form submit button and replace all given placeholder text dynamically using the fields name.

The custom submit action stores all the values in a list of key values pairs with the name of the field being the key. Input fields that would return a list are processed to return a comma separated string.

public class StoreFormInSessionSubmit : SubmitActionBase<string>
{
    public StoreFormInSessionSubmit(ISubmitActionData submitActionData) : base(submitActionData)
    {
    }

    protected override bool TryParse(string value, out string target)
    {
        target = string.Empty;
        return true;
    }

    protected override bool Execute(string data, FormSubmitContext formSubmitContext)
    {
        Assert.ArgumentNotNull(formSubmitContext, nameof(formSubmitContext));

        if (!formSubmitContext.HasErrors)
        {
            Logger.Info($"Form {formSubmitContext.FormId} submitted successfully.");

            var formValues = GetFormValues(formSubmitContext.Fields);

            HttpContext.Current.Session["form"] = formValues;
        }
        else
        {
            Logger.Warn($"Form {formSubmitContext.FormId} submitted with errors: {string.Join(", ", formSubmitContext.Errors.Select(t => t.ErrorMessage))}.");
        }

        return true;
    }

    private List<KeyValuePair<string, string>> GetFormValues(IList<IViewModel> form)
    {
        var formValues = new List<KeyValuePair<string, string>>();

        foreach (var inputField in form)
        {
            var inputFieldValue = GetFormValue(inputField);

            formValues.Add(new KeyValuePair<string, string>(inputField.Name, inputFieldValue));
        }

        return formValues;
    }

    private string GetFormValue(object field)
    {
        var value = field?.GetType().GetProperty("Value")?.GetValue(field, null);
        if (value is IList)
        {
            var enumerableValue = value as IList<string>;
            return string.Join(",", enumerableValue.ToArray());
        }
        else
        {
            return value?.ToString() ?? string.Empty;
        }
    }
}

The custom form element is simply based of the standard text element but when rendering the text value, loops through all the key value pairs retrieved from the session and replaces all placeholder text found in the form element.

[Serializable]
public class PersonalizedText : FieldViewModel
{
    public string Text { get; set; }

    protected override void InitItemProperties(Item item)
    {
        base.InitItemProperties(item);
        Text = StringUtil.GetString(item.Fields["Text"]);

        if (!string.IsNullOrEmpty(Text))
        {
            var formValues = (IList<KeyValuePair<string, string>>) HttpContext.Current.Session["form"];

            ReplacePlaceholderText(formValues);
        }
    }

    protected override void UpdateItemFields(Item item)
    {
        base.UpdateItemFields(item);

        item.Fields["Text"]?.SetValue(Text, true);
    }

    private void ReplacePlaceholderText(IList<KeyValuePair<string, string>> formValues)
    {
        if (formValues != null && formValues.Any())
        {
            foreach (var formValue in formValues)
            {
                var placeholder = '*' + formValue.Key + '*';
                Text = Text.Replace(placeholder, formValue.Value);
            }
        }
    }

For reference:

Creating a custom submit action

Creating a custom form element

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.