Mohammad AbuJaffal's blog

Sitecore, .NET and other blogs
Menu
  • Home
Home
Sitecore
Sitecore Forms
Show progress indicator while submitting Sitecore Form
Sitecore

Show progress indicator while submitting Sitecore Form

Mohammad Abujaffal August 12, 2021

In one of the projects I worked on, a client asked to show some sort of progress indicator when submitting a Form. The forms were built using Sitecore Forms with Sitecore Forms Extensions on a 9.1.1 version of the Sitecore platform.

My first thought was to add a special class on the button from the Forms Dashboard, and using JavaScript and CSS make the loading happen on click event of the button. It sounded simple, but I start getting all strange behaviors, plus I know that Sitecore Forms uses jQuery Unobtrusive Ajax, so I start digging into how this library handles the JavaScript functions of actually submitting the form.

I came across this great article Using jQuery Unobtrusive AJAX in ASP.NET Core Razor Pages, It has a table that details the custom attributes that control the behavior of jQuery Unobtrusive AJAX

AttributeDescription
data-ajaxMust be set to true to activate unobtrusive Ajax on the target element.
data-ajax-confirmGets or sets the message to display in a confirmation window before a request is submitted.
data-ajax-methodGets or sets the HTTP request method (“Get” or “Post”).
data-ajax-modeGets or sets the mode that specifies how to insert the response into the target DOM element. Valid values are before, after and replace. Default is replace
data-ajax-loading-durationGets or sets a value, in milliseconds, that controls the duration of the animation when showing or hiding the loading element.
data-ajax-loadingGets or sets the id attribute of an HTML element that is displayed while the Ajax function is loading.
data-ajax-beginGets or sets the name of the JavaScript function to call immediately before the page is updated.
data-ajax-completeGets or sets the JavaScript function to call when response data has been instantiated but before the page is updated.
data-ajax-failureGets or sets the JavaScript function to call if the page update fails.
data-ajax-successGets or sets the JavaScript function to call after the page is successfully updated.
data-ajax-updateGets or sets the ID of the DOM element to update by using the response from the server.
data-ajax-urlGets or sets the URL to make the request to.

I figured I could use data-ajax-loading or data-ajax-begin to solve my problem, I ended up using data-ajax-begin, as I didn’t want to add an HTML element on each of the forms I have, instead, I’ll call a JavaScript function that add a class on the Submit button, which has CSS rules defined that will show the animation.

The Implementation

When I inspect the form element in the browser, to see those data attributes, I found only a few are implemented, data-ajax-begin is not one of them.

With the help of dotPeak, I found out that Sitecore has a pipeline to initialize those attributes.

public class InitializeAjaxOptions : MvcPipelineProcessor<RenderFormEventArgs>
  {
    private readonly IFormRenderingContext _formRenderingContext;

    public InitializeAjaxOptions(IFormRenderingContext formRenderingContext)
    {
      Assert.ArgumentNotNull((object) formRenderingContext, nameof (formRenderingContext));
      this._formRenderingContext = formRenderingContext;
    }

    public override void Process(RenderFormEventArgs args)
    {
      Assert.ArgumentNotNull((object) args, nameof (args));
      if (!args.ViewModel.IsAjax)
        return;
      if (args.HtmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
      {
        IDictionary<string, object> unobtrusiveHtmlAttributes = new AjaxOptions()
        {
          HttpMethod = "Post",
          InsertionMode = InsertionMode.ReplaceWith,
          UpdateTargetId = args.FormHtmlId,
          OnSuccess = FormattableString.Invariant(FormattableStringFactory.Create("$.validator.unobtrusive.parse('#{0}');$.fxbFormTracker.parse('#{1}');", (object) args.FormHtmlId, (object) args.FormHtmlId))
        }.ToUnobtrusiveHtmlAttributes();
        foreach (string key in (IEnumerable<string>) unobtrusiveHtmlAttributes.Keys)
          args.Attributes[key] = unobtrusiveHtmlAttributes[key];
      }
      if (!args.IsPost)
      {
        args.QueryString.Add("fxb.FormItemId", (object) args.ViewModel.ItemId.ToGuid());
        args.QueryString.Add("fxb.HtmlPrefix", (object) this._formRenderingContext.Prefix.Trim('.'));
      }
      args.RouteName = "FormBuilder";
    }
  }

So I created a new pipeline to replace it, which would add the data attributes I need.

 public class InitializeAjaxOptions : MvcPipelineProcessor<RenderFormEventArgs>
    {
        private readonly IFormRenderingContext _formRenderingContext;

        public InitializeAjaxOptions(IFormRenderingContext formRenderingContext)
        {
            Assert.ArgumentNotNull((object)formRenderingContext, nameof(formRenderingContext));
            this._formRenderingContext = formRenderingContext;
        }

        public override void Process(RenderFormEventArgs args)
        {
            Assert.ArgumentNotNull((object)args, nameof(args));
            if (!args.ViewModel.IsAjax)
                return;
            if (args.HtmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
            {
                IDictionary<string, object> unobtrusiveHtmlAttributes = new AjaxOptions()
                {
                    HttpMethod = "Post",
                    InsertionMode = InsertionMode.ReplaceWith,
                    UpdateTargetId = args.FormHtmlId,
                    OnSuccess = FormattableString.Invariant(FormattableStringFactory.Create("$.validator.unobtrusive.parse('#{0}');$.fxbFormTracker.parse('#{1}');", (object)args.FormHtmlId, (object)args.FormHtmlId)),
                    OnBegin = "OnBegin",                 
                }.ToUnobtrusiveHtmlAttributes();

                foreach (string key in unobtrusiveHtmlAttributes.Keys)
                    args.Attributes[key] = unobtrusiveHtmlAttributes[key];
            }
            if (!args.IsPost)
            {
                args.QueryString.Add("fxb.FormItemId", (object)args.ViewModel.ItemId.ToGuid());
                args.QueryString.Add("fxb.HtmlPrefix", (object)this._formRenderingContext.Prefix.Trim('.'));
            }
            args.RouteName = "FormBuilder";
        }
    }    

This line (OnBegin = “OnBegin”) will add the data-ajax-begin attribute to all forms, with the value “OnBegin” which is the JavaScript function I’ll need to write.

The JavaScript function is very simple I’ll just select all buttons with a specific class, and add another class.

  OnBegin = function (xhr) {            
            $(".loader-button").addClass("loader");
        }

With help of a Front End developer, I added the CSS rules that will create the animation when the user submits the form.

Of course don’t forget to add the patch configuration file for the new pipeline.

<forms.renderForm>      
        <processor type="Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.InitializeAjaxOptions, Sitecore.ExperienceForms.Mvc">
          <patch:attribute name="type">ProjectX.Feature.Forms.Pipelines.RenderForm.InitializeAjaxOptions, 
ProjectX.Feature.Forms</patch:attribute>
        </processor>
      </forms.renderForm>

That’s it, and it worked as expected.

Share
Tweet
Email
Prev Article

Related Articles

Every beginning has a story and here is mine with …

My Sitecore story

Data Importer
I started working on a new Sitecore project recently, and …

Import Sitecore Items using SPE

About The Author

Mohammad Abujaffal

Mohammad Abu Jaffal is a Sitecore Developer at Tanasuk Technologies. He is an experienced .net developer, has been coding professionally since 2007, writing a variety of software applications ranging from command-line, desktop to web applications. He also has been leading teams of developers, successfully delivering projects., worked for local and international companies during his career in software development. Mohammad's passion lies deep in architecture and everything cloud.

Recent Posts

  • Show progress indicator while submitting Sitecore Form
  • View Sitecore Forms in Groups or Categories in Forms Dashboard
  • How to place a Sitecore Form in a pop up.

Recent Comments

  • Sitecore Symposium 2018 after 1 month, recap – XtremDev on Sitecore Symposium 2018, My First Symposium
  • Seethalakshmi on My Sitecore story
  • Rodrigo Peplau on My Sitecore story

Archives

  • August 2021
  • November 2020
  • September 2020
  • January 2020
  • November 2018
  • October 2018
  • September 2018
  • August 2018

Mohammad AbuJaffal's blog

Sitecore, .NET and other blogs
Copyright © 2023 Mohammad AbuJaffal's blog

Ad Blocker Detected

Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Refresh