Web Forms for Marketers (WFFM) ‒ Part 3 ‒ Multipart Form, Custom Save Action and a Summary Page with a Custom Validator


Put it all together!

The Registration form consists of three steps. In the first step you can choose a seminar and participants. In the second step you have to fill out address details and at least the third step is a tricky summary page with a custom Summary field which inherits from ListControl, displaying the title of the seminar, all participants and the final price for all the persons.

Step 1

Step 1

Step 2

Step 2

Step 3

Step 3

Now, we know how the form looks like. But there are a lot of things we should take a closer look! 😉

The topmost question is: How to do a multi step form on a single page? There are a few examples in the web where each step has a success page (the next step) Multistep forms using WFFM (webforms for marketeers)

That wasn’t a solution for me, because we have to stay on the current page, there are several seminars on the page in different categories. We can’t expect from the customer to create three success pages for each seminar… that would be hundreds of pages!

Much better!! We create a custom SuccessRedirect-Pipeline and patched it before the Sitecore.Form.Core.Pipelines.FormSubmit.SuccessRedirect-Pipeline.

Configuration

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <pipelines>
            <processMessage>
                <processor type="Project.Infrastructure.Pipelines.Form.ProcessSeminarMessage, Project.Infrastructure" patch:before="processor[@method='SendEmail']"/>
            </processMessage>
            <successAction>
                <processor type="Project.Infrastructure.Pipelines.SuccessRedirect, Project.Infrastructure" patch:before="processor[@type='Sitecore.Form.Core.Pipelines.FormSubmit.SuccessRedirect, Sitecore.Forms.Core']"/>
            </successAction>
        </pipelines>
    </sitecore>
</configuration>

 

SuccessRedirect-Pipeline

public class SuccessRedirect : ClientPipelineArgs
{
    private const string RegistrationFormularAnchor = "#SeminarRegistrationContainer";

    public void Process(SubmitSuccessArgs args)
    {
        Assert.IsNotNull(args, "args");
        if (args.Form == null)
        {
            return;
        }
        if (args.Form.ID != ItemIds.Forms.SeminarRegistrationStep1 && args.Form.ID != ItemIds.Forms.SeminarRegistrationStep2)
        {
            return;
        }
        var url = GetRedirectUrlForRegistrationFormular(args);
        if (string.IsNullOrEmpty(url))
        {
            return;
        }
        args.AbortPipeline();
        WebUtil.Redirect(url, true);
    }

    private string GetRedirectUrlForRegistrationFormular(SubmitSuccessArgs args)
    {
        var url = LinkManager.GetItemUrl(Context.Item);

        WebUtil.RemoveQueryString(url);

        var parameter = new[] {"step", "2"};
        if (args.Form.ID == ItemIds.Forms.SeminarRegistrationStep1)
        {
            return WebUtil.AddQueryString(url, parameter) + RegistrationFormularAnchor;
        }
        if (args.Form.ID == ItemIds.Forms.SeminarRegistrationStep2)
        {
            parameter = new[] {"step", "3"};
            return WebUtil.AddQueryString(url, parameter) + RegistrationFormularAnchor;
        }
        return url;
    }
 }

The code is quite simple! All three Forms are added in standard values as a rendering. I check the form-id which is submitted and add a parameter to the url like ?step=2. On the Seminar Form  Page I simply have to check the parameter in the url and display the appropriate form.

Such easy is multistep form redirection!!! 😀

Summary Field

All fields which are neccessary for the summary field and the final email-message are tagged:

Tag

In this case we are able to get all Submits (form-steps) from the current Analytics Session and we can use them to show a summary with informations submitted in Step 1. I displayed the chosen Seminar Title included the Seminar Appointment (date and location) and all applicants, also submitted in form step 1.

Code looks like this:

[ValidationProperty("Value")]
public class SeminarFormSummary : ListControl
{
    private const string baseCssClassName = "scfSummaryListBorder";
    private AppointmentModel _appointment;
    private SeminarModel _seminar;
    private IField _seminarRadioListField;
    private string _validationValue;
    protected RadioButtonList bulletedList = new RadioButtonList();

    public SeminarFormSummary(HtmlTextWriterTag tag) : base(tag)
    {
        CssClass = baseCssClassName;
        Inject();
    }

    public SeminarFormSummary() : this(HtmlTextWriterTag.Div)
    {
        Inject();
    }

    [Inject]
    public IFormService FormService { get; set; }

    [Inject]
    public ISeminarSummaryControlFactory SeminarSummaryControlFactory { get; set; }

    public override string ID
    {
        get { return base.ID; }
        set
        {
            title.ID = value + "text";
            bulletedList.ID = value + "scope";
            base.ID = value;
        }
    }

    public override ControlResult Result
    {
        get
        {
           return new ControlResult(ControlName,  _validationValue ?? string.Empty,  string.Empty);
        }
    }

    protected override System.Web.UI.WebControls.ListControl InnerListControl
    {
        get { return bulletedList; }
    }

    [DefaultValue("scfSummaryListBorder")]
    [VisualProperty("Css Class:", 600)]
    [VisualFieldType(typeof (CssClassField))]
    public new string CssClass
    {
        get { return base.CssClass; }
        set { base.CssClass = value; }
    }

    public string Value
    {
        get
        {
            var stringBuilder = new StringBuilder();
            foreach (var listItem in InnerListControl.Items.Cast<ListItem>().Where(listItem => listItem.Selected))
            {
                stringBuilder.AppendFormat("<item>{0}</item>", listItem.Value);
            }
            return stringBuilder.ToString();
        }
    }

    private void Inject()
    {
        var bs = new Bootstrapper();
        bs.Kernel.Inject(this);
    }

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        bulletedList.CssClass = "scfSummaryList";
        help.CssClass = "scfSummaryListUsefulInfo";
        title.CssClass = "scfSummaryListLabel";
        title.Text = GetTitle();
        generalPanel.CssClass = "scfSummaryListGeneralPanel";
        Controls.AddAt(0, generalPanel);
        Controls.AddAt(0, title);
        generalPanel.Controls.AddAt(0, help);
        generalPanel.Controls.AddAt(0, bulletedList);
    }

    private string GetTitle()
    {
        var seminarTitle = string.Empty;
        if (_seminar != null)
        {
            seminarTitle += string.Format("<h2>{0}</h2>", _seminar.Title);
        }
        if (_appointment != null)
        {
            seminarTitle += string.Format("<h4>{0}, {1}</h4>",
            _appointment.DateTimeFrom.ToLongDateString(),
            _appointment.Location);
        }
        seminarTitle += string.Format("<h6>{0}</h6>", Translator.Translate("Teilnehmer"));
        return seminarTitle;
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        title.AssociatedControlID = null;
    }

    protected override void InitItems(ListItemCollection collection)
    {
        var formStep1 = FormService.GetSubmit(ItemIds.Forms.SeminarRegistrationStep1, AnalyticsTracker.SessionId);
        if (formStep1 != null)
        {
            _seminarRadioListField = FormService.GetField(formStep1, new Guid(FieldIds.Forms.SeminarRegistration.Seminars));
            if (_seminarRadioListField != null && !string.IsNullOrEmpty(_seminarRadioListField.Value))
            {
                GetAppointmentAndSeminar(_seminarRadioListField.Value);
            }
        }

        if (_seminar == null)
            return;

        var participantsCollection = SeminarSummaryControlFactory.CreateParticipantsListItemCollection();
        base.InitItems(participantsCollection);
    }

    private void GetAppointmentAndSeminar(string value)
    {
        var context = new SitecoreContext();
        _appointment = context.GetItem<AppointmentModel>(new Guid(value));
        _seminar = (_appointment != null) ? context.GetItem<SeminarModel>(_appointment.ParentItem.Id) : null;
        _validationValue = value;
    }
 }

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.