Kentico EMS: MVC Widget Experiments Part 3 - Rendering Form Builder Forms Without Widgets
Tags: kentico, aspnet, mvc, cms
Published: 2020-06-08 14:01:50

---
title: Kentico EMS: MVC Widget Experiments Part 3 - Rendering Form Builder Forms Without Widgets
published: true
description: Learn how to display Kentico Form Builder forms without using Widgets or the Page Builder in MVC.
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/j23c9c1r0k5dv1qmv4fn.jpg
tags: kentico, aspnet, mvc, cms
series: Kentico EMS - MVC Widget Experiments
---

## Widget Experiments

_This series dives into Kentico 12 MVC Widgets and the related technologies that are part of Kentico's Page Builder technology - Widget Sections, Widgets, Form Components, Inline Editors, and Dialogs 🧐._

_Join me 👋, as we explore the nooks and crannies of Kentico EMS MVC Widgets and discover what might be possible with this powerful technology..._

> _If you aren't yet familiar with Kentico MVC Widgets, check out Kentico's Youtube video on [Building a Page with MVC Widgets in Kentico](https://www.youtube.com/watch?v=ljQO9on5lLM)._

> The technique described below is no longer necessary in Kentico Xperience 13, which fully supports [rendering widgets in code](https://docs.xperience.io/developing-websites/page-builder-development/rendering-widgets-in-code).

## Goals

This post is going to explore a way we can render a Form Builder Form statically, without Widgets or the Page Builder 😎.

> Note: The core of the approach discussed below came from [Lee Conlin](https://devnet.kentico.com/users/454146/lee-conlin)'s post 👍 [Using forms in Kentico 12 MVC without the page builder](https://medium.com/distinctionuk/using-forms-in-kentico-12-mvc-without-the-page-builder-22e42ba4ab04), but I think my example is even simpler.

## Use Case - Displaying a Form in the Page Footer

Imagine a content manager of our Kentico 12 MVC site wants a "Contact Us" form, managed by Kentico's [Form Builder](https://docs.kentico.com/k12sp/developing-websites/form-builder-development) feature, to appear in the footer of the site.

Well, that's not a problem 😉! Thinking back to my last post, we remember that MVC [Editable Areas](https://docs.kentico.com/k12sp/developing-websites/page-builder-development/creating-pages-with-editable-areas-in-mvc) (and therefore Widgets) can be placed in the `_Layout.cshtml` of the app.

{% post seangwright/kentico-ems-mvc-widget-experiments-part-2-where-can-widgets-be-used-o9m %}

We also know that we can define an Editable Area specifically for Forms by using the `@Html.Kentico().FormArea("...")` extension method in our View 😄.

Perfect!

We open our `_Layout.cshtml` and drop the Form Area right in the footer.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <!-- ... -->
</head>
<body>
    <!-- ... -->

    @RenderBody()

    <footer>
      @Html.Kentico().FormArea("layout-footer-form")
    </footer>

    <!-- ... -->
</body>
</html>
```

All done, right 🙄?

## Problem - Page Builder's Single Page Context

Unfortunately this solution doesn't really solve our problem. The Content Manager wants the same form in the footer for the entire site.

Sure, they could add a form via the Page Builder interface in the CMS for a couple pages, but if the site has 100 pages... or 1,000 pages 😱?

The issue here is that every MVC Widget added to a page is only added to the Editable Area _on that specific page_.

Even if the Editable Area is defined in a place that appears on every page (like the `<footer>`), it still has to be populated with Widgets (including our Form Widget) on a per-page basis 🤔.

This is good in some circumstances, like when we want pages to be independent - editing Widgets on one page doesn't affect the Widgets on any other page.

But in this specific circumstance we want the exact same form displayed on every single page without any additional work by the Content Manager 😫.

## Solution - Render Using Built-in Kentico APIs

We're going to solve this problem by rendering the form ourselves using the APIs that Kentico exposes.

Since we won't be using the Page Builder functionality, the selection and rendering of the Form won't be page-dependent 💪🏾.

### Render Using Child Actions

First, to get the Form to render in the `_Layout.cshtml`, we're going to need to use a Child Action.

Going back to our Layout markup, we can change it to the following:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <!-- ... -->
</head>
<body>
    <!-- ... -->

    @RenderBody()

    <footer>
      @{ Html.RenderAction(
           actionName: "Form", 
           controllerName: "Form", 
           routeValues: new { formName = "ContactUs" })
    </footer>

    <!-- ... -->
</body>
</html>
```

We call our Child Action, passing the name of the specific Form we want to display, in this case `"ContactUs"`.

### Define the Controller

Now we need a Controller with an Action Method to handle this render call:

```csharp
public class FormController : Controller
{
    private readonly IFormProvider formProvider;
    private readonly IFormComponentVisibilityEvaluator visibilityEvaluator;

    public FormController(
      IFormProvider formProvider,
      IFormComponentVisibilityEvaluator visibilityEvaluator
    {
        this.formProvider = formProvider;
        this.visibilityEvaluator = visibilityEvaluator;
    }

    [ChildActionOnly]
    public ActionResult Form(string formName) => 
        PartialView(CreateFormModel(formName);

    private FormWidgetViewModel CreateFormModel(string formName)
    {
        // ...
    } 
}
```

We create our view model, which is an instance of Kentico's `FormWidgetViewModel`. We are using this model because are going to reuse pieces from the View Kentico uses to render Forms as Widgets 🤓.

The code in `CreateFormModel` can be sourced directly from [Lee Conlin's post 🧐](https://medium.com/distinctionuk/using-forms-in-kentico-12-mvc-without-the-page-builder-22e42ba4ab04), but I'll reproduce it here for convenience:

```csharp
var formInfo = BizFormInfoProvider
    .GetBizFormInfo(formName, SiteContext.CurrentSiteName);

string className = DataClassInfoProvider
    .GetClassName(formInfo.FormClassID);

var existingBizFormItem = className is null
    ? null
    : BizFormItemProvider
        .GetItems(className)?.GetExistingItemForContact(
           formInfo, contactContext.ContactGuid);

var formComponents = formProvider
    .GetFormComponents(formInfo)
    .GetDisplayedComponents(
      ContactManagementContext.CurrentContact, 
      formInfo, existingBizFormItem, visibilityEvaluator);

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    TypeNameHandling = TypeNameHandling.Auto,
    StringEscapeHandling = StringEscapeHandling.EscapeHtml
};

var formConfiguration = JsonConvert.DeserializeObject<FormBuilderConfiguration>(
    formInfo.FormBuilderLayout, settings);

var prefix = Guid.NewGuid().ToString();

// Thanks to Dave in the comments for noticing this assignment is required
ViewData.TemplateInfo.HtmlFieldPrefix = prefix;

return new FormWidgetViewModel
{
    DisplayValidationErrors = true,
    FormComponents = formComponents.ToList(),
    FormConfiguration = formConfiguration,
    FormName = formName,
    FormPrefix = prefix,
    IsFormSubmittable = true,
    SiteForms = new List<SelectListItem>(),
    SubmitButtonImage = formInfo.FormSubmitButtonImage,
    SubmitButtonText = string.IsNullOrEmpty(formInfo.FormSubmitButtonText) 
      ? ResHelper.GetString("general.submit")
      : ResHelper.LocalizeString(formInfo.FormSubmitButtonText)
};
```

> This code is in the `FormController` for example purposes only. If you use this in your project, add proper error handling and move this logic out of the controller and into [something like a request handler](https://github.com/jbogard/MediatR/wiki#basics) 👍🏿.

### Use Kentico's View Code

Now that we are able to get all the required parts for rendering a Form Builder form, we can use Kentico's pre-built view code for rendering Form Widgets, which is pretty simple:

```csharp
<!-- ~/Views/Form/Form.cshtml -->

@using Kentico.Forms.Web.Mvc;
@using Kentico.Forms.Web.Mvc.Widgets;
@using Kentico.Forms.Web.Mvc.Widgets.Internal

@model FormWidgetViewModel

@{
    var config = FormWidgetRenderingConfiguration.Default;

    // @Html.Kentico().FormSubmitButton(Model) requires 
    // this ViewData value to be populated. Normally it
    // executes as part of the Widget rendering, but since
    // we aren't rendering a Widget, we have to do it manually

    ViewData.AddFormWidgetRenderingConfiguration(config);
}

@using (Html.Kentico().BeginForm(Model))
{
    @Html.Kentico().FormFields(Model)

    @Html.Kentico().FormSubmitButton(Model)
}
```

This code is sourced from Kentico's pre-compiled `_FormWidget.cshtml`.

This means our statically rendered Form will render the same way as a Form Widget, and submission of the Form will submit to Kentico's existing `FormWidgetController` - no need to handle any of this ourselves 👏🏽!

Our code can also handle the static rendering of _any_ Form Builder Form 😉, all we need to do is pass a different `formName` parameter when calling `@{ Html.RenderAction("Form", "Form", new { formName = "..." }); }` in our views.

### Caveats - It's Not A Widget

Because our approach isn't actually rendering a Widget (it isn't running in the context of the Page Builder), we lose out on some functionality...

Specifically, we don't have access to [the custom events](https://docs.kentico.com/k12sp/developing-websites/form-builder-development/customizing-the-form-widget) that get called when a Form Widget's Form Builder form is being rendered 😑.

These events are a powerful way to customize the markup surrounding the Form and its elements and are called by Kentico's internal Widget processing code.

Unfortunately we don't have access to it so we can't even duplicate it in our own code 😒.

Another limitation of not using the Form Widget to render our form is we can't use the Page Builder Form Widget form selector drop down to swap out the form 🤷🏽‍♂️.

Of course, we could add a custom field to a Page Type or define a CMS setting that would hold the `formName` value of the Form to be rendered. This requires just a little more setup on our end.

## Conclusion

Although there are some caveats to using the above approach when rendering Form Builder forms without using Widgets and the Page Builder, the benefits definitely outweigh them 💯.

It's also convenient that we can contain all the functionality for populating the `FormWidgetViewModel` behind a single Controller Child Action and the view code is very minimal.

I hope you find this little MVC Widget experiment useful - I know it's been helpful for the projects I work on.

I'd also like to thank Lee for providing the building blocks and inspiration for this post 😎.

...

As always, thanks for reading 🙏!

---

<figcaption>Photo by <a href="https://unsplash.com/@sctgrhm">Scott Graham</a> on Unsplash</figcaption>

---

We've put together a list over on [Kentico's GitHub account](https://github.com/Kentico/Home/blob/master/RESOURCES.md) of developer resources. Go check it out!

If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:

{% tag kentico %}

Or my Kentico blog series:

- [Kentico 12: Design Patterns](https://dev.to/search?q=Kentico%2012%3A%20Design%20Patterns)
- [Kentico CMS Quick Tips](https://dev.to/search?q=Kentico%20CMS%20Quick%20Tip)