Linked Selection Custom Fields in EPiServer Forms

Linked Selection Custom Fields in EPiServer Forms

In one of my projects I had to deal with a not that unusual requirement, be able to create a form with several selection fields which related or linked to each other. What do I mean with this is that if a selection field changes its value. another selection field will see its values changed due to the first selection.

epi_server_logo_detail

So in order to deal with this. I did the following:

  1. Create a custom key value pair property to store the values that should be shown to the user
  2. Create a custom selection form field block
  3. Create a view for the new custom field which must be handle the on change event using JavaScript
  4. Configure the fields in the editor interface

So without more hustle lets code !!!

Create a custom key value pair property

We will use a simple class to store the data


    [DataContract(Name = "keyValueItem")]

    public class KeyValueItem

    {

        public KeyValueItem()

        {

        }

        public KeyValueItem(string key, string value)

        {

            Key = key;

            Value = value;

        }

        [DataMember(Name = "key")]

        public string Key { get; set; }

        [DataMember(Name = "value")]

        public string Value { get; set; }

    }

Then we will create a property definition class that uses the new class


    [PropertyDefinitionTypePlugIn]

    public class KeyValueItemCollectionProperty : PropertyListBase

    {

    }

Create a custom selection form field block

Now that we have the classes needed to save the selection field related information. We will create a new custom selection field which must inherit from SelectionElementBlock


    [ContentType(DisplayName = "Custom Selection Field"

        , GUID = "2bddaade-be4f-48d4-abb8-522903f9b489"

        , GroupName = "Selection Custom Fields"

        , Description = "A selection custom element.")]

    public class CustomSelectionElementBlock : SelectionElementBlock

    {

        // The linked selection field which is going to be affected

        // when the user changes the value of this custom selection field

        public virtual string LinkedSelectionElementId { get; set; }

        // This is the field which will contain the related selection

        // field information

        [EditorDescriptor(EditorDescriptorType = typeof(CollectionEditorDescriptor))]

        public virtual IList LinkedSelectionFieldMappings { get; set; }

        public override void SetDefaultValues(ContentType contentType)

        {

            base.SetDefaultValues(contentType);

            AllowMultiSelect = false;

        }

    }

Create a view for the new custom field

Now we will create the view for this new selection custom field. We can use as base the view for the basic selection custom fields which can be found under the path inside the zip file:

{PROJECT_PATH}\modules\_protected\EPiServer.Forms\EPiServer.Forms.zip\Views\ElementBlocks\SelectionElementBlock.ascx

This file is an asp.net web form view so we will have to convert it to a razor view. In addition we will add some JavaScript to handle the change event on the selection custom field


@using EPiServer.Forms.Helpers.Internal

@model CustomSelectionElementBlock

@{

    var formElement = Model.FormElement;

    var labelText = Model.Label;

    var placeholderText = Model.PlaceHolder;

    var defaultOptionItemText = !string.IsNullOrWhiteSpace(placeholderText) ? placeholderText : Html.Translate($"/episerver/forms/viewmode/selection/{(Model.AllowMultiSelect ? "selectoptions" : "selectanoption")}");

    var defaultOptionSelected = Model.Items.Count(x => x.Checked.HasValue && x.Checked.Value)  x.Key, x => x.Value);

    var linkedElementId = Model.LinkedSelectionElementId;

}

    var dictValues = @Html.Raw(Json.Encode(mappingsLinkedField));

    function changeFunc() {

        var selectBox = document.getElementById("@formElement.Guid");

        var selectedValue = selectBox.options[selectBox.selectedIndex].value;

        // Clear first

        var quantityDropDown = $("select[name='__field_@linkedElementId']");

        if (quantityDropDown == null) {

            return;

        }

        removeOptions(document.getElementById(quantityDropDown.attr('id')));

        var otherValues = dictValues[selectedValue].split(",");

        for (var i = 0; i = 1 ; i--)

        {

            selectbox.remove(i);

        }

    }

@using (Html.BeginElement(Model, new { @class = "FormSelection" + Model.GetValidationCssClasses(), data_f_type = "selection" }))

{

    @labelText

        @defaultOptionItemText

        @foreach (var item in items)

        {

            var defaultSelectedString = Model.GetDefaultSelectedString(item);

            var selectedString = string.IsNullOrEmpty(defaultSelectedString) ? string.Empty : "selected";

                @item.Caption

        }

    @Html.ValidationMessageFor(Model)

}

We define two new variables: mappingsLinkedField and linkedElementId. The first variable is the mapping dictionary of values for the linked selection field and the second variable is the id of that linked field

In addition, we created two functions changeFunc and removeOptions. The first function will try to find the selection field using the id in the variable linkedElementId. If it finds it, it will remove the items inside the field by calling the function removeOptions and later it will create the new values from the dictionary. The dictionary will have a structure similar to this:

Key | Value

1 | 5,6,7,8

2 | 9,11,2,1

3 | 7,6,5

When the value of the custom selection field is changed. We use that value as key to retrieve the values of the dictionary and plug them in the linked selection field.

The view must be inside the ElementBlocks shared directory /Views/Shared/ElementBlocks/CustomSelectionElementBlock.cshtml

Configure the fields in the editor interface

Now we will go to the CMS editor interface to create a new form and see how we can configure our new custom selection field. First we create a new form container

1a

We will add two selection fields. The first selection field is the new custom selection field and the second is a normal selection field which is going to be the one to be linked

1b

We will get the id of the normal selection field and saved it somewhere for later. This field should not have any data because it is going to be filed with the information from the mappings of the custom selection field

1c

We will now edit the custom selection field and add the following items:

Name | Value

First | 1

Second | 2

Third | 3

Followed by the mappings based on the values of the items

Key | Value

1 | 1,2,4,5

2 | 5,7,8,9

3 | 4,6,7,8

And finally we will set the saved if of the normal selection field inside the LinkedSelectionElementId text box

1d

The result will be a normal selection field which will be filled with the data based on the current value of the custom selection field

1e

I hope it will help someone and keep learning !!!

Written by:

Jorge Cardenas

Developer with several years of experience who is passionate about technology and how to solve problems through it.

View All Posts

Leave a Reply