Episerver Forms Submission -CRUD Operations with client side validations

344 Views Asked by At

I have used an EpiServer form.1 custom validation in the form is on File name that i am uploading which should not be same. So If I fill in the form ,the file that is being uploaded should not have the same name. To achieve this, I have added a file name element that is going to save just the file name by extracting the fileupload url. This is done on the forms submitting event.

Additionally ,I am using this form data to display in a kendo grid. So here’s how the UI is. Also, the File Name element that i have added in form container will be displayed in the grid rather than the file upload url.

enter image description here

The form works as expected with the custom validation. However, for the custom validation, I have created a FormsInitialization module for the same with Forms Submitting event to validate the form. So rather than having a forms initialization on the server side ,i would like to handle this on client side itself. So the question is

1- can I move the custom validation on client side provided I need to get the list of file names from the submitted data & check if the current submitted form file name doesn't have any existing one with the same name. In short there is an ajax call for the same. I have referred

https://world.optimizely.com/forum/developer-forum/CMS/Thread-Container/2016/7/episerver-forms---overwriting-submission-data/

for form submission. The concept in the link shown is to overwrite,which i am using to write file name extracting it from file upload ,comparing with existing form data submission & overwriting the same. Here's my forms initialization module with form submitting event:

    
using EPiServer;
using EPiServer.Core;
using EPiServer.Forms.Core;
using EPiServer.Forms.Core.Data;
using EPiServer.Forms.Core.Events;
using EPiServer.Forms.Core.Models;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Usi.EpiServer.Business.Initialization
{
    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class OptimizelyFormsEventsInitializationModule : IInitializableModule
    {
        private IFormRepository _formRepository;
        private IFormDataRepository _formDataRepository;
        private IContentLoader _contentLoader;


        public void Initialize(InitializationEngine context)
        {
            _formRepository = ServiceLocator.Current.GetInstance<IFormRepository>();
            _formDataRepository = ServiceLocator.Current.GetInstance<IFormDataRepository>();
            _contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();

            var formsEvents = ServiceLocator.Current.GetInstance<FormsEvents>();
            formsEvents.FormsSubmitting += OnFormSubmitting;
        }

        private void OnFormSubmitting(object sender, FormsEventArgs e)
        {
            var formsSubmittingEventArgs = e as FormsSubmittingEventArgs;
            var content = _contentLoader.Get<IContent>(e.FormsContent.ContentLink);
            var localizable = content as ILocalizable;
            if (content == null || localizable == null || formsSubmittingEventArgs == null)
            {
                return;
            }

            var formIdentity = new FormIdentity(e.FormsContent.ContentGuid, localizable.Language.Name);
            ValidateAndAddFileNameForInvestorSecureForm(formIdentity, formsSubmittingEventArgs);
        }

        private void ValidateAndAddFileNameForInvestorSecureForm(FormIdentity formIdentity, FormsSubmittingEventArgs formsSubmittingEventArgs)
        {
            var friendlyNameInfos = _formRepository.GetDataFriendlyNameInfos(formIdentity).ToList();

            var fileUploadFriendlyNameInfo = friendlyNameInfos.FirstOrDefault(x => x.FriendlyName.Equals("File Upload", StringComparison.InvariantCultureIgnoreCase));
            if (fileUploadFriendlyNameInfo == null)
            {
                return;
            }
            var fileNameFriendlyNameInfo = friendlyNameInfos.FirstOrDefault(x => x.FriendlyName.Equals("File Name", StringComparison.InvariantCultureIgnoreCase));
            var kvpFileUpload = formsSubmittingEventArgs.SubmissionData.Data.FirstOrDefault(kvp => kvp.Key == fileUploadFriendlyNameInfo.ElementId);
            var kvpFileName = formsSubmittingEventArgs.SubmissionData.Data.FirstOrDefault(kvp => kvp.Key == fileNameFriendlyNameInfo?.ElementId);
            var fileName = kvpFileUpload.Value.ToString().Substring(kvpFileUpload.Value.ToString().LastIndexOf("@", StringComparison.InvariantCultureIgnoreCase) + 1);
            formsSubmittingEventArgs.SubmissionData.Data.Remove(kvpFileName);

            kvpFileName = new KeyValuePair<string, object>(kvpFileName.Key, fileName);
            if (IsFileNameExists(formIdentity, kvpFileName.Value.ToString()).Result)
            {
                formsSubmittingEventArgs.CancelAction = true;
                formsSubmittingEventArgs.CancelReason = $"{kvpFileName.Value} already exists.Please upload a file with a different name.";
            }
            else
            {
                formsSubmittingEventArgs.SubmissionData.Data.Add(kvpFileName);
            }
        }

        private Task<bool> IsFileNameExists(FormIdentity formIdentity, string fileName)
        {
            var submissionData = _formDataRepository.GetSubmissionData(formIdentity,
                DateTime.MinValue, DateTime.Now).Select(submission => submission.Data);
            var fileNames = submissionData
                .Select(dicObj => dicObj.Select(kvpObj => new KeyValuePair<string, object>(_formRepository.GetDataFriendlyNameInfos(formIdentity)
                         .FirstOrDefault(friendlyNameInfo => friendlyNameInfo.ElementId == kvpObj.Key)
                         ?.FriendlyName, kvpObj.Value)).ToList()
                    .Select(kvp => kvp)
                    .FirstOrDefault(kvp => kvp.Key.Equals("File Name", StringComparison.InvariantCultureIgnoreCase))
                    .Value.ToString())
                .ToList();

            return Task.FromResult(fileNames.Contains(fileName));
        }

        public void Uninitialize(InitializationEngine context)
        {
            var formsEvents = ServiceLocator.Current.GetInstance<FormsEvents>();
            formsEvents.FormsSubmitting -= OnFormSubmitting;
        }
    }
}

Here rather than having form submitting event on server side,i want to move this to client side validation that will not just validate the duplicate file name validation but also add the file name into the form submission. I have referred https://optimizely.blog/2017/10/customizing-episerver-forms-with-client-events-build-a-quiz/

for client side validation but here's the issue with the events not getting fired.

Since i have a kendo grid that gets the data from formrepository class which is what i bind it to kendo grid. So technically its not just submitting the form but also getting all the existing form submission data on every page load. due to which the form submitting event doesn't fire.

Here's my .js code that i want to incorporate the form submitting event client side.

(($) => {
    $(".optimizely-form-grid-block").each(function (index) {
        const optimizelyFormGridBlock = $(this);
        const blockId = optimizelyFormGridBlock[index].getAttribute("data-block-id");
        const isApproverGroupAccess = optimizelyFormGridBlock[index].getAttribute("data-is-approver-group-access").toLowerCase() === "true" ? true : false;
        const optimizelyFormGridBlockContainer = optimizelyFormGridBlock.find(".optimizely-form-grid-block__container")[0];
        const url = "/api/public/optimizelyformgridblock/GetFormSubmissionData";

        const formData = new FormData();
        formData.append("BlockId", blockId);
        formData.append("__RequestVerificationToken", optimizelyFormGridBlock.find("input:hidden[name=__RequestVerificationToken]")[index].value);

        fetch(url, { method: "POST", body: formData }).then((resp) => {
            return resp.json();
        }).then((data) => {
            console.log(data);
            data.SubmissionData.length > 0 ? optimizelyFormGridBlockContainer.hidden = false : optimizelyFormGridBlockContainer.hidden = true;
            bindGrid(data, optimizelyFormGridBlock.find(".optimizely-form-grid-block__grid"), isApproverGroupAccess);
            return data;
        }).catch((error) => {
            console.log(error);
        });

    });

    function bindGrid(data, gridSection, isApproverGroupAccess) {
        var formGuid = data.FormIdentity.Guid;
        var columns = generateColumns(data.SubmissionData);

        gridSection.kendoGrid({
            dataSource: {
                data: data.SubmissionData, pageSize: 10
            },
            columns:
                [
                    { columns }
                ],
            dataBound: function () {
                $(".k-grid-delete span").addClass("fa fa-trash").text("");
                $(".k-grid-show span").addClass("fas fa-folder-open").text("");
            },
            columnMenu: {
                filterable: false
            },
            pageable: true,
            sortable: true,
            resizable: true,
            filterable: true,
            toolbar: ["excel", "search"]
        });

        function generateColumns(dataSource) {
            let columns = [];

            if (dataSource.length > 0) {
                columns = Object.keys(dataSource[0]).map(function (name) {
                    // skip fields that are system generated or not required
                    if (name.indexOf("SYSTEMCOLUMN_") !== -1 ||
                        name === "Submitted from" ||
                        name === "Finalized" ||
                        name === "Submission Id" ||
                        name.toLowerCase() === "File Upload".toLowerCase()) {
                        return null;
                    }

                    return {
                        field: name,
                        //By user & Time are EpiServer forms generated fields that captures user name that submitted the form & time respectively.
                        title: name === "By user" ? "Created By" : (name === "Time" ? "Created Date" : name)
                    };
                }).filter(function (column) {
                    return column !== null;
                });
            }

            // add a new column for actions with custom command buttons
            columns.push({
                title: "Actions",
                command: [
                    {
                        name: "delete",
                        text: "Delete",
                        visible: function () { return isApproverGroupAccess },
                        click: function (e) {
                            if (confirm("Are you sure you want to delete this item?")) {
                                const dataItem = this.dataItem($(e.currentTarget).closest("tr"));
                                const submissionId = dataItem["Submission Id"];

                                $.ajax({
                                    url: '/api/public/optimizelyformgridblock/delete',
                                    type: 'POST',
                                    data: { formGuid: formGuid, submissionId: submissionId },
                                    success: function (response) {
                                        window.location.reload();
                                    },
                                    error: function (xhr, status, error) {
                                        if (xhr.status === 403) {
                                            alert("You do not have access rights to delete the file.");
                                        }
                                    }
                                });
                            } else {
                                return;
                            }
                        }
                    },
                    {
                        name: "show",
                        text: "Show",
                        click: function (e) {
                            e.preventDefault();
                            const dataItem = this.dataItem($(e.currentTarget).closest("tr"));
                            const fileUpload = Object.keys(dataItem).find(key => key.toLowerCase() === "file upload") || "File Upload";
                            window.open(dataItem[fileUpload], "_blank");
                        }
                    }
                ]
            });

            return columns;
        }
    };
})(jQuery);

2- Does Episerver form submission provide an api to modify the submission form. So on the grid that i have right now, i add an edit icon that will fetch the data based on submission id(getting the data based on submission id is doable & has a method as well in formrepository) ,edit the submitted form on UI & resubmit it that it updates the form.

In summary, the entire implementation works as expected with the above code mentioned. Two of the things that I want to achieve is:

1- Episerver form submitting event on client side

2- Editting an existing form submission data.

Any input is appreciated.

0

There are 0 best solutions below