We have moved!

You are currently looking at documentation for Umbraco 8 and older versions.
Go to docs.umbraco.com for documentation for Umbraco 9 and newer versions.

    Adding a server-side event handlers to Umbraco Forms

    The samples in this article applies to Umbraco Forms version 8 and later versions.

    Form validation event

    Add a new class to your project and have it inherit from IUserComposer, implement the Compose() method. This method will contain a handler for the FormValidate event.

    using System.Linq;
    using System;
    using System.Collections.Generic;
    using Umbraco.Core.Composing;
    
    namespace Forms8.EventHandlers
    {
        /// <summary>
        /// Catch form submissions before being saved and perform custom validation.
        /// </summary>
        public class FormEventsComposer : IUserComposer
        {
    
            public void Compose(Composition composition)
            {
                // Attach a handler to the `FormValidate` event of UmbracoForms
                Umbraco.Forms.Web.Controllers.UmbracoFormsController.FormValidate += FormsController_FormValidate;
            }
    
            private void FormsController_FormValidate(object sender, Umbraco.Forms.Mvc.FormValidationEventArgs e)
            {
                // If needed, be selective about which form submissions you affect
                if (e.Form.Name == "Form Name")
                {
                    // Access the Controller that handled the Request
                    var controller = sender as Umbraco.Forms.Web.Controllers.UmbracoFormsController;
    
                    // Check the ModelState
                    if (controller == null || !controller.ModelState.IsValid)
                        return;
    
                    // A sample validation
                    var email = GetPostFieldValue(e, "email");
                    var emailConfirm = GetPostFieldValue(e, "verifyEmail");
    
                    // If the validation fails, return a ModelError
                    if (email.ToLower() != emailConfirm.ToLower())
                        controller.ModelState.AddModelError(GetPostField(e, "verifyEmail").Id.ToString(), "Email does not match");
    
                }
            }
    
            // Helper method
            private static string GetPostFieldValue(Umbraco.Forms.Mvc.FormValidationEventArgs e, string key)
            {
                var field = GetPostField(e, key);
    
                if (field == null)
                {
                    return string.Empty;
                }
                
                var value = e.Context.Request[field.Id.ToString()] ?? "";
                return value.Trim();
            }
    
            // Helper method
            private static Umbraco.Forms.Core.Models.Field GetPostField(Umbraco.Forms.Mvc.FormValidationEventArgs e, string key)
            {
                return e.Form.AllFields.SingleOrDefault(f => f.Alias == key);
            }
    
        }
    }
    

    The FormValidate event will pass a reference to the Controller and Form objects. Use them to check ModelState and Form Field values. If validation fails, return a ModelError.

    Service events

    The services available via interfaces IFormService, IFolderService, IDataSourceService and IPrevalueSourceService are used when forms definitions are stored within the Umbraco database. They expose the following events that are triggered just before or after an entity handled by the service is modified:

    • Creating
    • Created
    • Deleting
    • Deleted
    • Saving
    • Saved
    • Updating
    • Updated

    The "-ing" events allow for the entity being changed to be modified before the operation takes place, or to cancel the operation. The "-ed" events fire after the update is complete.

    Both can be wired up using a composer and component:

        public class TestSiteComposer : IUserComposer
        {
            public void Compose(Composition composition)
            {
                composition.Components().Append<TestSiteComponent>();
            }
        }
    
        public class TestSiteComponent : IComponent
        {
            private readonly IFormService _formService;
    
            public TestSiteComponent(IFormService formService)
            {
                _formService = formService;
            }
    
            public void Initialize()
            {
                _formService.Saving += FormService_Saving;
                _formService.Saved += FormService_Saved;
            }
    
            private void FormService_Saving(object sender, FormEventArgs e)
            {
                // Modify before saving.
                e.Form.Name += " (updated)";
    
                // Cancel the operation.
                e.Cancel = true;
            }
    
            private void FormService_Saved(object sender, FormEventArgs e)
            {
            }
    
            public void Terminate()
            {
                _formService.Saving -= FormService_Saving;
                _formService.Saved -= FormService_Saved;
            }
        }
    

    When a form or folder is moved there is no specific service event. However information available in the AdditionalData dictionary available on the FormEventArgs or FolderEventArgs can be used to determine whether the item was moved, and if so, where from:

        public class TestSiteComposer : IUserComposer
        {
            public void Compose(Composition composition)
            {
                composition.Components().Append<TestSiteComponent>();
            }
        }
    
        public class TestSiteComponent : IComponent
        {
            private readonly IFormService _formService;
    
            public TestSiteComponent(IFormService formService)
            {
                _formService = formService;
            }
    
            public void Initialize()
            {
                _formService.Updating += FormService_Updating;
                _formService.Updated += FormService_Updated;
            }
    
            private void FormService_Updated(object sender, FormEventArgs e) =>
                Current.Logger.Info(
                    typeof(TestSiteComponent),
                    $"Form updated. New parent: {e.Form.FolderId}. Old parent: {e.AdditionalData["MovedFromFolderId"]}");
    
            private void FolderService_Updated(object sender, FolderEventArgs e) =>
                Current.Logger.Info(
                    typeof(TestSiteComponent),
                    $"Folder updated. New parent: {e.Folder.ParentId}. Old parent: {e.AdditionalData["MovedFromFolderId"]}");
    
            public void Terminate()
            {
                _formService.Updating -= FormService_Updating;
                _formService.Updated -= FormService_Updated;
            }
        }
    

    If a folder is being moved, the key within the AdditionalData dictionary is "MovedFromParentId".

    Backoffice entry rendering events

    When an entry for a form is rendered in the backoffice, and event is available to allow modification of the record details before they are presented to the user. This is shown in the following example:

        public class TestSiteComposer : IUserComposer
        {
            public void Compose(Composition composition)
            {
                composition.Components().Append<TestSiteComponent>();
            }
        }
    
        public class TestSiteComponent : IComponent
        {
            private readonly IFormRecordSearcher _formRecordSearcher;
    
            public TestSiteComponent(IFormRecordSearcher formRecordSearcher)
            {
                _formRecordSearcher = formRecordSearcher;
            }
    
            public void Initialize()
            {
                _formRecordSearcher.EntrySearchResultFetching += FormRecordSearcher_EntrySearchResultFetching;
            }
    
            public void FormRecordSearcher_EntrySearchResultFetching(object sender, EntrySearchResultEventArgs e)
            {
                var transformedFields = new List<object>();
                foreach (var field in e.EntrySearchResult.Fields)
                {
                    if (field?.ToString() == "Test")
                    {
                        transformedFields.Add("Test (updated)");
                    }
                    else
                    {
                        transformedFields.Add(field);
                    }
                }
    
                e.EntrySearchResult.Fields = transformedFields;
            }
    
            public void Terminate()
            {
                _formRecordSearcher.EntrySearchResultFetching -= FormRecordSearcher_EntrySearchResultFetching;
            }
        }