Sitecore 10 Forms and special characters in list controls

When you create forms in Sitecore Forms, it provides you with functionality to managing multilingual forms setup. Creating a new form each control in the form will be created as a separate item for each specific control. But in the case of list fields where each list item is created as a static list item (and list items not rendered from existing items), for the item name Sitecore uses the field value if the field name/label is empty. All good, all good – until you want to use a not valid character in the field value/label like ë, ä etc. Then Sitecore overrides the value to be item name compliant. And therefor, the values in the list control will be changed to item name compliant values. Sitecore simply removes/deletes the incompliant characters. But is that really what you want? Don’t you want to be able to use language specific characters to be displayed or stored from your list control?


The issue is that Sitecore uses the ItemUtil.ProposeValidItemName for creating the display name for the item. Making Sitecore Forms compliant with these characters, then instead of using the ProposeValidItemName when creating the items, we will simply use the listFieldItem.Text or listFieldItem.Value.



As an example we replace the I"temUtil.ProposeValidItemName(listFieldItem.Text) : ItemUtil.ProposeValidItemName(listFieldItem.Value)" with "listFieldItem.Text : listFieldItem.Value"

(from Sitecore.ExperienceForms.Mvc.DataSource.DataSourceSettingsManager.UpdateStaticItems()):  

using System;

using System.Collections.Generic;

using System.Globalization;

using Sitecore;

using Sitecore.Data;

using Sitecore.Data.Items;

using Sitecore.Diagnostics;

using Sitecore.ExperienceForms.Extensions;

using Sitecore.ExperienceForms.FieldSettings;

using Sitecore.ExperienceForms.Mvc.Constants;

using Sitecore.ExperienceForms.Mvc.DataSource;

using Sitecore.ExperienceForms.Mvc.Models;

 

namespace Norican.Infrastructure.Web.Sc.Forms

{

    public class DataSourceSettingsManagerWithDisplayName : DataSourceSettingsManager

    {

        protected override void UpdateSettings(

            ListFieldItemCollection settings,

            Item fieldSettingsItem,

            FieldSettingsContext settingsContext)

        {

            Assert.ArgumentNotNull((object)settings, nameof(settings));

            Assert.ArgumentNotNull((object)fieldSettingsItem, nameof(fieldSettingsItem));

            Assert.ArgumentNotNull((object)settingsContext, nameof(settingsContext));

            if (settingsContext.FieldItem == null)

                return;

            if (MainUtil.GetBool(settingsContext.FieldItem.Fields["Is Dynamic"]?.Value, false))

            {

                foreach (Item child in fieldSettingsItem.Children)

                    child.Recycle();

            }

            else

            {

                string displayFieldName = settingsContext.FieldItem.Fields["Display Field Name"]?.Value;

                string valueFieldName = settingsContext.FieldItem.Fields["Value Field Name"]?.Value;

                this.UpdateStaticItemsInternal((List<ListFieldItem>)settings, fieldSettingsItem, displayFieldName, valueFieldName);

            }

        }

 

        protected void UpdateStaticItemsInternal(

      List<ListFieldItem> items,

      Item fieldSettingsItem,

      string displayFieldName,

      string valueFieldName)

        {

            Assert.ArgumentNotNull((object)items, nameof(items));

            Assert.ArgumentNotNull((object)fieldSettingsItem, nameof(fieldSettingsItem));

            for (int index = 0; index < items.Count; ++index)

            {

                ListFieldItem listFieldItem = items[index];

                if (string.IsNullOrEmpty(listFieldItem.Value))

                {

                    listFieldItem.ItemId = "";

                }

                else

                {

                    string str = ItemUtil.ProposeValidItemName(listFieldItem.Value);

                    Item obj = ID.IsID(listFieldItem.ItemId) ? fieldSettingsItem.Database.GetItem(listFieldItem.ItemId, fieldSettingsItem.Language) : (Item)null;

                    if (obj == null)

                        obj = this.AddItem(str, fieldSettingsItem, new TemplateID(TemplateIds.ListFieldTemplateId));

                    else if (!obj.Axes.IsDescendantOf(fieldSettingsItem))

                        obj = obj.CopyTo(fieldSettingsItem, str);

                    listFieldItem.ItemId = obj?.ID.ToString() ?? string.Empty;

                    if (obj != null)

                    {

                        if (string.IsNullOrEmpty(valueFieldName))

                            valueFieldName = obj.Template.IsBasedOnTemplate(TemplateIds.ListFieldTemplateId) ? "Value" : "__ItemName";

                        obj.Editing.BeginEdit();

                        obj.Name = str;

                        obj.Fields[valueFieldName]?.SetValue(listFieldItem.Value, false);

 

                        /* Use item text or item value as displayName.

                           Original Sitecore code uses ItemUtil.ProposeValidItemName:

                           ... ItemUtil.ProposeValidItemName(listFieldItem.Text) : ItemUtil.ProposeValidItemName(listFieldItem.Value); */

                        (string.IsNullOrEmpty(displayFieldName) || obj.Fields[displayFieldName] == null ? obj.Fields[FieldIDs.DisplayName] : obj.Fields[displayFieldName])?.

                            SetValue(!string.IsNullOrEmpty(listFieldItem.Text) ? listFieldItem.Text : listFieldItem.Value, false);

                        

                        obj.Fields[FieldIDs.Sortorder]?.SetValue((index * 100).ToString((IFormatProvider)CultureInfo.InvariantCulture), false);

                        obj.Editing.EndEdit();

                    }

                }

            }

            foreach (Item child1 in fieldSettingsItem.Children)

            {

                Item child = child1;

                if (!items.Exists((Predicate<ListFieldItem>)(li => child.ID.ToString().Equals(li.ItemId, StringComparison.OrdinalIgnoreCase))))

                    child.Delete();

            }

        }

    }

}



And adding it to the config file: 

<sitecore>

  <services>

      <register patch:instead="register[@implementationType='Sitecore.ExperienceForms.Mvc.DataSource.DataSourceSettingsManager, Sitecore.ExperienceForms.Mvc']" serviceType="Sitecore.ExperienceForms.FieldSettings.IFieldSettingsManager`1[[Sitecore.ExperienceForms.Mvc.Models.ListFieldItemCollection, Sitecore.ExperienceForms.Mvc]], Sitecore.ExperienceForms" implementationType="Norican.Infrastructure.Web.Sc.Forms.DataSourceSettingsManagerWithDisplayName, Norican.Infrastructure" lifetime="Transient" />

    </services>

</sitecore>













No comments: