Hades
Hades

Reputation: 1985

How to use BizForms in Kentico 12 without page builder

Kentico 12 only supports forms using the "Form" page-builder widget out of the box.

Can anyone provide examples of how one might utilise BizForms on an MVC _Layout.cshtml or in pages that do not use the page builder?

Acceptance criteria:

Upvotes: 2

Views: 1315

Answers (4)

seangwright
seangwright

Reputation: 18225

The OP posted a blog about how to make this work.

The solution requires using some of Kentico's internal APIs for Form Builder rendering with Form Widgets and putting that code into a Controller action.

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

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

I took that idea and wrote a follow up post, Kentico EMS: MVC Widget Experiments Part 3 - Rendering Form Builder Forms Without Widgets, which shows we can also use Kentico's pre-built Form Widget view code to also get the expected rendering and form submission functionality.

<!-- ~/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)
}

Upvotes: 2

Yuriy Sountsov
Yuriy Sountsov

Reputation: 198

The Form widget is rendered using a combination of the following view structure and the view model FormWidgetViewModel:

using (Ajax.Kentico().BeginForm( ... ))
{
    @Html.AntiForgeryToken()

    @Html.Kentico().FormFields(Model.FormComponents, Model.FormConfiguration, FormFieldRenderingConfiguration.Widget)

    // Render Model.SubmitButtonImage using @Html.Kentico().ImageInput( ... )
    // Or render a plain <input> using Model.SubmitButtonText
}

If you have the BizFormInfo object for the form, it is needed for the following properties:

new FormWidgetViewModel
{
    FormName = formInfo.FormName,
    FormConfiguration = IFormBuilderConfigurationRetriever.Retrieve(formInfo),
    FormComponents = IFormProvider.GetFormComponents(formInfo).GetDisplayedComponents( ... ),
    FormPrefix = // This may be optional outside of the Page Builder context,
    SubmitButtonText = formInfo.FormSubmitButtonText,
    SubmitButtonImage = formInfo.FormSubmitButtonImage
}

Inside Ajax.Kentico().BeginForm you can pass in the controller and action handling the form.

Use methods in IFormProvider to update or add the form submission and to send emails.

Update (see comments):

IFormBuilderConfigurationRetriever is marked internal, so it is not directly accessible. Its implementation in turn uses IFormBuilderConfigurationSerializer to deserialize formInfo.FormBuilderLayout. That interface is also marked internal. Further, the implementation of that interface uses the internal FormBuilderTypesBinder.

This means that there is no API available to retrieve Model.FormConfiguration. As of Kentico 12.0.16, you would need to recreate the internal functionality. The basic implementation is like this:

JsonConvert.DeserializeObject<FormBuilderConfiguration>(formInfo.FormBuilderLayout, new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        TypeNameHandling = TypeNameHandling.Auto,
        SerializationBinder = // Set to the internal FormBuilderTypesBinder, which validates only known form builder types
        StringEscapeHandling = StringEscapeHandling.EscapeHtml
    });

Upvotes: 1

Alen Genzić
Alen Genzić

Reputation: 1418

You can take a look at the Kentico.Forms.Web.Mvc.Widgets namespace in your MVC project (it should be included by default).

In there is a KenticoFormWidgetController controller class which renders form partials and accepts form submissions. You could possibly use the Index route of that controller to render a partial of your form, however it is unknown to me how exactly the route looks.

If you have source code access to Kentico you could check the internals of it by yourself.

Upvotes: 0

Roman Hutnyk
Roman Hutnyk

Reputation: 1549

Hades, You might user Forms API (https://docs.kentico.com/api12/content-management/form-data) to save/access form data and implement completely custom layout for it. Hope that helps!

Upvotes: 0

Related Questions