Jul 07, 2020
Introduction
Sitecore Forms uses the jQuery Unobtrusive AJAX Library to handle basic client-side form functionality such as validations and submissions. Like with any other form that uses jQuery Unobtrusive AJAX, we can configure a form generated by Sitecore Forms to do additional client-side functionality when submitting it, such as the example I'm going to show you here on how to add a loading animation.
What do you need?
This example was done in Sitecore 9.1.1. For this example, I'm using Bootstrap 4.4.1, you can link to the CDN version or download a local copy. In the back-end Visual Studio project, you will need to add NuGet packages for Sitecore.ExperienceForms, Sitecore.ExperienceForms.Mvc, Sitecore.Kernel, Sitecore.Mvc, Sitecore.Mvc.Analytics. Remember to correctly set up your layout with an outer layout so the required styles and scripts for Sitecore Forms are rendered. (You can find a guide on adding a form to a web page in Sitecore here.) Don't forget to include a link for Bootstrap in the outer layout's head declaration.
How to implement?
Build a form in Sitecore, create a "container" view rendering, create a page, and include the "container" rendering and a form inside of it. You can build any kind of form, for this example I have built a two-page form with a "thank you" third page, and styled it using Bootstrap:
If you take a look at the form's generated HTML code, you will see that the <form>
tag has several "data-ajax-" attributes. These are the jQuery Unobtrusive AJAX attributes. (You can read more about Unobtrusive AJAX here.) We want to add a "data-ajax-loading" attribute to the form, so it shows/hides the specified HTML element when an AJAX request is in process.
Edit the "container" view rendering to contain the HTML for the loading animation. In this example, we are using a spinner animation provided by Bootstrap. As you can see, it has "display: none" set so it doesn't show up the first time you load the form.
Container.cshtml
<section class="container-fluid">
<div class="row">
<div class="col-md-3">
@Html.Sitecore().Placeholder("form")
</div>
</div>
<!-- The following is the spinner animation provided by Bootstrap -->
<div id="loader" class="spinner-border" style="display: none" role="status">
<span class="sr-only">Loading...</span>
</div>
</section>
Sitecore uses Pipelines to configure the form before rendering it. We can tap into this pipeline (specifically, the forms.renderForm
pipeline) to add options to the form. First, let's create our pipeline class that will handle the creation of our "data-ajax-loading" attribute that will be added to the form:
InitAjaxAdditionalOptions.cs
namespace Oshyn.Forms.Samples.Pipelines
{
public class InitAjaxAdditionalOptions : MvcPipelineProcessor<RenderFormEventArgs>
{
public string LoadingElementId { get; set; }
public override void Process(RenderFormEventArgs args)
{
Assert.ArgumentNotNull(args, "args");
if (!args.ViewModel.IsAjax || !args.HtmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{
return;
}
var additionalAjaxOptions = new AjaxOptions
{
LoadingElementId = LoadingElementId
};
var attributes = additionalAjaxOptions.ToUnobtrusiveHtmlAttributes();
foreach (var key in attributes.Keys)
{
args.Attributes[key] = attributes[key];
}
}
}
}
This class has a property, LoadingElementId
, that we can set up in our config patch file (more on that later). That value is assigned to an AjaxOptions
object's LoadingElementId
property. The properties from AjaxObject
are converted to HTML attributes using the ToUnobtrusiveHtmlAttributes()
call, and added to the pipeline's RenderFormEventArgs
object that will be used at the end of the pipeline to render the HTML. LoadingElementId
will be rendered as the "data-ajax-loading" attribute.
Create your config patch file to add the new custom pipeline. Add it AFTER the InitializeAjaxOptions pipeline provided by Sitecore. Set the <LoadingElementId>
property to the HTML id of the spinner (in this specific example, "loader"). Make sure to deploy this file under App_Config\Include
Oshyn.Forms.Samples.config
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<forms.renderForm>
<processor patch:after="processor[@type='Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.InitializeAjaxOptions, Sitecore.ExperienceForms.Mvc']"
type="Oshyn.Forms.Samples.Pipelines.InitAjaxAdditionalOptions, Oshyn.Forms.Samples">
<LoadingElementId>loader</LoadingElementId>
</processor>
</forms.renderForm>
</pipelines>
</sitecore>
</configuration>
Deploy your code to your Sitecore environment, and reload your form. When doing any type of submit/navigation action (i.e., pressing buttons), you will see the animation appear (the animation will be longer if you just deployed, or if your submit actions take longer to process):
If you view at the page source code, you will see that the <form>
tag now includes a data-ajax-loading="#loader"
attribute.
This solution is not limited to just displaying a loader. If you need more flexibility, such as calling specific JS functions before and after an AJAX call, you can add other Unobtrusive AJAX attibutes such as data-ajax-begin
and data-ajax-complete
:
InitAjaxAdditionalOptions.cs
namespace Oshyn.Forms.Samples.Pipelines
{
public class InitAjaxAdditionalOptions : MvcPipelineProcessor<RenderFormEventArgs>
{
public string LoadingElementId { get; set; }
public string OnBegin { get; set; } //Added this property
public string OnComplete { get; set; } //Added this property
public override void Process(RenderFormEventArgs args)
{
Assert.ArgumentNotNull(args, "args");
if (!args.ViewModel.IsAjax || !args.HtmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{
return;
}
//Added OnBegin and OnComplete
var additionalAjaxOptions = new AjaxOptions
{
LoadingElementId = LoadingElementId,
OnBegin = OnBegin,
OnComplete = OnComplete
};
var attributes = additionalAjaxOptions.ToUnobtrusiveHtmlAttributes();
foreach (var key in attributes.Keys)
{
args.Attributes[key] = attributes[key];
}
}
}
}
Make sure to add to the config patch file the <OnBegin>
and <OnComplete>
properties set to the JS functions you want to call:
Oshyn.Forms.Samples.config
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<forms.renderForm>
<processor patch:after="processor[@type='Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.InitializeAjaxOptions, Sitecore.ExperienceForms.Mvc']"
type="Oshyn.Forms.Samples.Pipelines.InitAjaxAdditionalOptions, Oshyn.Forms.Samples">
<LoadingElementId>loader</LoadingElementId>
<OnBegin>beginAjaxCall</OnBegin>
<OnComplete>completeAjaxCall</OnComplete>
</processor>
</forms.renderForm>
</pipelines>
</sitecore>
</configuration>
Deploy, open the form in a browser, and look at the source code. You will see that the <form>
element now has the data-ajax-begin="beginAjaxCall"
and data-ajax-complete="completeAjaxCall"
attributes. Make sure you have defined your beginAjaxCall()
and completeAjaxCall()
functions somewhere in your HTML JS code or referred custom JS file.
WARNING: under any circumstances, NEVER attempt to replace/add the following Unobtrusive AJAX attributes: data-ajax-success (OnSuccess)
, data-ajax-method (HttpMethod)
, data-ajax-mode (InsertionMode)
, data-ajax-update (UpdateTargetId)
. These are reserved for use by Sitecore Forms.
References
Add a form to a web page by Sitecore.
Using jQuery Unobtrusive AJAX in ASP.NET Core Razor Pages by Learn Razor Pages.
Related Insights
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.