WFFM Overriding the FormID chosen in the Presentation Details

463 views Asked by At

In a certain scenario I need to programmatically change the WFFM Form presented in the Form Renderer. The Form Renderer itself is added to a Placeholder via the Presentation Details.

I am able to access the Form Render and set the FormID and update its parameters to the ID of the Form I want to display instead. However, its as if Sitecore isn't honouring these properties and displaying the original form even when I move my code earlier in the page life cycle e.g. Page_Init. My code is as follows

    // Pass in controls of the sublayout
    public FormRender SetFormRender(Control control, string dataSource)
    {
        FormRender formRender = null;

        // loop through controls contained in passed in control
        foreach (Control child in control.Controls)
        {
            if (child is FormRender)
            {
                formRender = child as FormRender;
                if (formRender != null)
                {
                    formRender.FormID = dataSource;
                    formRender.Parameters = "FormID=" + HttpUtility.HtmlEncode(dataSource);
                    break;
                }
            }

            // If control has controls pass to this method for recursion 
            if (control.HasControls())
            {
                var nestedFormRender = SetFormRender(child, dataSource);
                if (nestedFormRender != null && formRender == null)
                {
                    formRender = nestedFormRender;
                    break;
                }

            }
        }

        return formRender;
    }
3

There are 3 answers

0
Jonathan Robbins On BEST ANSWER

I found a resolution based on Mike Reynolds blog as Ahmed Okour suggested got me 50% of the way there but required additional work.

I created a new FormRender that exposed a public property for the overriding Form Id to be passed. This new FormRender implements the existing one however overriding the base OnInit() still produces a protected method meaning it can't be called when we need it. Therefore I created a non-overriding public OnInit() method:

public class PublicFormRender : FormRender
{
    public string OverridingFormId { get; set; }

    public void OnInit()
    {
        OnInit(new EventArgs());
    }

    protected override void OnInit(System.EventArgs e)
    {
        // New logic added here so overriding Id is always honoured
        // especially in the case of PublicFormRender is added via the FrontEnd
        if (!string.IsNullOrEmpty(OverridingFormId))
        {
            FormID = OverridingFormId;
            var parameters = WebUtil.ParseUrlParameters(Parameters);
            if (parameters["FormID"] != null)
                parameters["FormID"] = HttpUtility.HtmlEncode(OverridingFormId);
            Parameters = parameters.ToString();
        }

        base.OnInit(e);
    }
}

I duplicated the FormRender in Sitecore at the path /sitecore/layout/Renderings/Modules/Web Forms for Marketers/, referencing the PublicFormRender and used that to add Forms in the Presentation Details

    public PublicIdFormRender SetFormRender(Control control, string dataSource)
    {
        PublicIdFormRender formRender = null;

        // Loop through to find the new PublicFormRender
        foreach (Control child in control.Controls)
        {
            var publicFormRender = child as PublicFormRender;
            if (publicFormRender != null)
            {
                // Set the new public property to the data source
                publicFormRender.OverridingFormId = dataSource;
                // Initialise the Form via the non-overriding public method
                publicFormRender.OnInit();
                formRender = publicFormRender;
                break;
            }

            if (control.HasControls())
            {
                var nestedFormRender = SetFormRender(child, dataSource);
                if (nestedFormRender != null && formRender == null)
                {
                    formRender = nestedFormRender;
                    break;
                }

            }
        }

        return formRender;
    }
0
Amir Setoudeh On

This is because the form is actually rendered when it is added to the control collection. If you must adhere to this architecture, my suggestions is to remove the control from the collection and then add it via

control.Controls.Add(formRender);

Not very efficient, but should work.

2
Ahmed Okour On

Maybe after you set FormID and Parameter you will need to recall FormRender.OnInit(), so your code could be like this:

....
formRender.FormID = dataSource;
formRender.Parameters = "FormID=" + HttpUtility.HtmlEncode(dataSource);
formRender.OnInit(null);                   
break;
....

Edit

I don't think you can call formRender.OnInit() from your code as its protected method, but what you can do is create a new control that inherits FormRender and replace the one on presentation details with this, and then override OnInit() method and place your code that handle FormID property, then call base.OnInit()

Mike Reynolds has a blog about how to load different forms based on query string here