Pages

Monday, October 11, 2021

How to Exclude or Modify Episerver Forms Samples Javascript and CSS

Optimizely Forms contains jQuery and CSS packages that are included for the Form rendering out-of-box. This isn't always desired because it can affect page performance, other styling, or it could have other side effects depending on your setup. Optimizely provides for the disabling of these files through the Forms.config file in the Forms module folder, which allows you to independently control the insertion of jQuery and CSS. However, this method is easy to break with an update. It also isn't very flexible since it's an all-or-nothing approach.

If you got to this article and just want to disable all Forms jQuery and/or CSS

You can disable all of the included jQuery and CSS using the Forms.config file. It is located at "modules\_protected\EPiServer.Forms\Forms.config".

Set injectFormOwnJQuery to false to stop inserting the forms jQuery.

Set injectFormOwnStylesheet to false to stop inserting the out-of-box forms styles.

An alternative approach is to create your own custom resource list.

This method replaces the included resource list with a custom one. Because of that, you have complete control over which resources are loaded or excluded, and you can even add your own. In my code below I have removed the Forms jQuery, added my own customFormScript.js, and left the rest of the OOB styles. 

One quick word of caution is that I am using the Internal ModuleHelper GetPublicVirtualPath. You're not supposed to rely on the Internal namespaced methods, but this one seems safe enough.

[pre class="brush:csharp;class-name:collapse-box;"]
using EPiServer.Forms.Helpers.Internal;
using EPiServer.Forms.Implementation;
using System;
using System.Collections.Generic;

namespace EpiSandbox.Models
{
    public class CustomFormResources : IViewModeExternalResources
    {
        public virtual IEnumerable<Tuple<string, string>> Resources
        {
            get
            {
                string publicVirtualPath = ModuleHelper.GetPublicVirtualPath("EPiServer.Forms.Samples");
                return new List<Tuple<string, string>>
                {
                    new Tuple<string, string>("script", "/resources/EpiForms/customFormScript.js"),
                    new Tuple<string, string>("script", publicVirtualPath + "/ClientResources/ViewMode/EPiServerFormsSamples.js"),
                    new Tuple<string, string>("css", publicVirtualPath + "/ClientResources/ViewMode/EPiServerFormsSamples.css"),
                    new Tuple<string, string>("css", publicVirtualPath + "/ClientResources/ViewMode/jquery-ui.min.css"),
                    new Tuple<string, string>("css", publicVirtualPath + "/ClientResources/ViewMode/jquery-ui.structure.min.css"),
                    new Tuple<string, string>("css", publicVirtualPath + "/ClientResources/ViewMode/jquery-ui.theme.min.css")
                };
            }
        }
    }
}
[/pre]

Wire it up with an InitializationModule

Because of the way the Forms Initialization module loads the resources, you can't simply add the CustomFormResources class to your IOC container. Using the common For<T>().Use<T>() would result in both sets of resources being loaded. Instead, you need to intercept the request for the included ViewModeExternalResources and replace the return list with the new custom one. Also, because we are only interested in replacing the resources included with Forms.Samples, we need to make sure that's the only one we replace.

[pre class="brush:csharp;class-name:collapse-box;"]
using EpiSandbox.Models;
using EPiServer.Forms.Implementation;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using System;

namespace EpiSandbox.Business.Initialization
{
    [ModuleDependency(typeof(EPiServer.Forms.EditView.InitializationModule))]
    public class FormsInitializationModule : IConfigurableModule
    {
        private ServiceConfigurationContext _context;

        public void Initialize(InitializationEngine context)
        {
            context.InitComplete += Context_InitComplete;
        }

        public void ConfigureContainer(ServiceConfigurationContext context)
        {
            _context = context;
        }

        private void Context_InitComplete(object sender, EventArgs e)
        {
            // The code below works to intercept requests and modify to use custom.
            _context.Services.Intercept<IViewModeExternalResources>((serviceLocator, resources) =>
            {
                if (resources is EPiServer.Forms.Samples.ViewModeExternalResources) { return new CustomFormResources(); }
                return resources;
            });
        }

        public void Uninitialize(InitializationEngine context)
        {
            // do nothing
        }
    }
}
[/pre]

The result

Benefits of this approach

  • While an upgrade could replace the Forms.config file and break that setting, this approach will still work, barring code changes.
  • You have control over each resource instead of just excluded all JS or all CSS
  • You can still use the included jQuery if you simply want to minify and use it
  • You can separate your custom Form CSS and JS from the rest of your site resources and only load it when needed

1 comment:

  1. Thanks for this, great solution.
    Is it possible to customize the resources that are used for specific elements e.g. AddressesElementBlock, DateTimeElementBlock, DateTimeRangeElementBlock and RecaptchaElementBlock? These elements use "extra" resources.

    ReplyDelete

Share your thoughts or ask questions...