Pages

Tuesday, November 9, 2021

Custom Optimizely Form Containers - Put the View Where You Want

Most instructions for creating a custom form block in Optimizely follow the same approach. My problem with the typical approach is that it requires a folder structure that doesn't match my solution. I use a slightly different method to allow me to move my Form Container Block rendering to my choice of folders.

My issue is with the Views/Shared/ElementsBlock folder structure

I typically use a feature-based folder approach for views. When not using that approach, however, I like to bring the view folders up out of Shared. This approach would work for either of those scenarios. For the purpose of this article, though, I am using the Views folder similar to the following image:

The typical instructions for creating a custom Form Container Block direct you to place a copy of the FormContainerBlock.ascx file into an ElementBlocks folder inside your Views/Shared folder. That structure doesn't match the idea behind the organization in the image above. I prefer to create a Forms folder instead, and keep the same structure and convention using the following steps.

Create a custom Form Container Block to start

[pre class="brush:csharp;class-name:collapse-box;"]
[ContentType(DisplayName = "Form Container", GUID = "d6b5bbce-c897-4e4f-bb54-d14cd6b8a3a7", Description = "Standard form container to use in Episerver.",
    GroupName = EPiServer.Forms.Constants.FormElementGroup_Container)]
[ServiceConfiguration(typeof(IFormContainerBlock))]
public class StandardFormContainerBlock : FormContainerBlock, IFormSubmitted
{
    [Ignore]
    [ScaffoldColumn(false)]
    public override Url RedirectToPage { get; set; }

    [Display(Name = "Refresh page after submitting form.", GroupName = "Information", Order = -6350)]
    [CultureSpecific]
    public virtual bool RefreshAfterSubmission { get; set; }
    public void OnSubmissionFinalized(object sender, FormsEventArgs e)
    {
        var submittedEventArgs = e as FormsSubmittedEventArgs;
        var formBlock = submittedEventArgs.FormsContent as StandardFormContainerBlock;
        if (submittedEventArgs != null && formBlock != null)
        {
            if (formBlock.RefreshAfterSubmission)
            {   // this happens after everything else is finished, so we can redirect without impact
                // note: this field is readonly on the OOB FormContainerBlock so we override and Ignore
                // that field on this class to make this work
                formBlock.RedirectToPage = new Url(HttpContext.Current.Request.UrlReferrer.AbsolutePath);
            }
        }
    }
}
[/pre]

 

This is the Form Container Block I use to replace the out-of-box one completely. This code uses my Form Events Interface pattern, and has properties for refreshing the current page after submission for creating gated content.

Copy the FormContainerBlock.ascx file

The source for the original FormContainerBlock.ascx file is available in the modules/_protected/EPiServer.Forms.zip file. Copy it from the Views/ElementBlocks folder and paste it into a folder of your choice. I prefer /Views/Forms to match my organization structure. You can rename the file if you want as well.

Finally, create a new controller with the following code

[pre class="brush:csharp"]
[TemplateDescriptor(AvailableWithoutTag = true,
                Default = true,
                ModelType = typeof(StandardFormContainerBlock),
                TemplateTypeCategory = TemplateTypeCategories.MvcPartialController
                )]
public class StandardFormContainerController : FormContainerBlockController
{
    public override ActionResult Index(FormContainerBlock currentBlock)
    {
        var result = base.Index(currentBlock) as PartialViewResult;
        result.ViewName = "/Views/Forms/FormContainerBlock.ascx";
        return result;
    }
}
[/pre]

 

This controller is slightly different from the typical one. The key here is to use the base Index method to get the PartialViewResult. Then, modify the ViewName used for that result to point to the FormContainerBlock.ascx file you just copied. 

It's a small change, but I have worked on several projects where multiple form container blocks were required, and this approach allows easier organization.

No comments:

Post a Comment

Share your thoughts or ask questions...