Selecting Dynamic Content in Native Sitefinity Modules with Custom Fields

By in
No comments

Sitefinity allows you to easily add simple custom fields to Content items using the backend administration, using the built-in field controls such as TextField. But what happens when you want to add a custom type and a custom field selector? The built-in custom field interface only allows a limited selection of field types, and the Unknown field isn’t much use since it doesn’t allow you to specify the type. sitefinity-custom-field-options Fortunately, as is often the case with Sitefinity, there is another way. This post will explore how you can leverage the Sitefinity API to add a custom field for linking Dynamic module content items, and automatically assign a custom Field selector generated by Sitefinity Thunder. Creating a Custom Field Selector for Dynamic Modules For this example, I’ve created a simple custom module called “Things” with just a simple title property.

sitefinity-module-builder-custom-module-things 

We’ll be using this module to select items from inside one of the native Sitefinity modules, in this case News. Using Sitefinity Thunder I then used the Dynamic Items Field Control Selector template to generate a custom-built selector for that module. This creates all the files including the field control class definition, frontend template, and associated JavaScript file to handle the behavior of selecting items from the Things module.

sitefinity-thunder-custom-module-selector-field-solution-files 

However, this template is actually specifically intended to create a “one-to-many” relationship between other custom dynamic types, not the native Sitefinity modules like News. As a result, the generated control comes out-of-the-box formatted and configured to work in that mode. Specifically, while the native Sitefinity modules have a default provider name of “OpenAccessProvider”, the Dynamic Modules provider name is “OpenAccessDataProvider”. So attempting to use this control as-is will result in the error “There is no configuration for data provider with the name of “OPENACCESSDATAPROVIDER” for “Telerik.Sitefinity.DynamicModules.DynamicModuleManager” when opening the selector. Fortunately, the fix for this is easy; we simply need to modify the generated JavaScript file to force the provider name to the expected “OpenAccessProvider” value. In the JavaScript file, locate the method set_providerName and change it to match the following code:

// Passes the provider to the control

    set_providerName: function (value) {

        if (value == 'OPENACCESSDATAPROVIDER' || value == 'OpenAccessDataProvider') value = 'OpenAccessProvider';

        var binder = this.get_itemsSelector();

        if (binder) {

            binder.set_providerName(value);

        }

        this._providerName = value;

}

Adding Custom Field Via API

The next step is to implement and run the code responsible for adding the custom field to the NewsItem content type. Best practices suggest you execute this code in Global.asax during the Bootstrapper.Initialized event at Application_Start. A great example of this is available in the Sitefinity Documentation for adding custom fields to the Order type in the Ecommerce module. To keep things simple for this example, I’m just going to implement this in the code-behind of a blank webform, which I’ll load manually to execute the following code:

public partial class InstallField : System.Web.UI.Page

    {

        CatalogManager catalogManager = CatalogManager.GetManager();

        ConfigManager configManager = ConfigManager.GetManager();

        MetadataManager metaManager = MetadataManager.GetManager();

        protected void Page_Load(object sender, EventArgs e)

        {

            AddFieldToModuleConfiguration<ThingsSelectorFieldElement>("Things", typeof(NewsItem), typeof(Guid[]), Config.Get<NewsConfig>(), NewsDefinitions.BackendDefinitionName, TypeResolutionService.ResolveType("SitefinityWebApp.Fields.ThingsSelectorFieldElement"));

        }

        /// <summary>

        /// Adds a custom field and selector to a Sitefinity module.

        /// </summary>

        /// <typeparam name="T"></typeparam>

        /// <param name="fieldName">Name of the field.</param>

        /// <param name="contentType">Sitefinity Content type.</param>

        /// <param name="fieldType">Type of the field to be added.</param>

        /// <param name="config">The Sitefinity Content Module Config.</param>

        /// <param name="definitionKey">The Backend Definition name for the Content Module.</param>

        /// <param name="fieldConfigElementType">Type of the field element for the custom selector.</param>

        public void AddFieldToModuleConfiguration<T>(string fieldName, Type contentType, Type fieldType, ContentModuleConfigBase config, string definitionKey, Type fieldConfigElementType) where T : FieldControlDefinitionElement

        {

            // Check if the NewsItem type has already been modified to contain meta fields

            if (metaManager.GetMetaType(contentType) == null)

            {

                // Create the metatype for the NewsItem class.

                metaManager.CreateMetaType(contentType);

                metaManager.SaveChanges();

            }

            // Add a new meta field to the Order table

            App.WorkWith()

                .DynamicData()

                .Type(contentType)

                .Field()

                .TryCreateNew(fieldName, fieldType)

                .SaveChanges(true);       

            // Get Backend views(e.g. Edit, Create) configuration

            var backendSection = config.ContentViewControls[definitionKey];

            var views = backendSection.ViewsConfig.Values.Where(v => v.ViewType == typeof(DetailFormView));

            // add custom field to each view

            foreach (DetailFormViewElement view in views)

            {

                // If there are no custom fields added before, the new field will be placed in the CustomFieldsSection

                var sectionToInsert = CustomFieldsContext.GetSection(view, CustomFieldsContext.customFieldsSectionName, fieldType.FullName);

                T newElement;

                try

                {

                    // Create a new instance of our field configuration in the current view configuration

                    newElement = Activator.CreateInstance(fieldConfigElementType, new object[] { sectionToInsert.Fields }) as T;

                }

                catch (Exception ex)

                {

                    throw;

                }

                // set field properties, default to Write mode

                newElement.DataFieldName = fieldName;

                newElement.FieldName = fieldName;

                newElement.DisplayMode = FieldDisplayMode.Write;

                // save field to view

                sectionToInsert.Fields.Add(newElement);

                configManager.SaveSection(config);

            }

        }

   }

  Note the different elements being passed to the method, which define the Sitefinity Content type, as well as the type of the custom field, and its associated definitions and module configuration, which are used by the method to create and assign the field and control. After building the page and running the code (be sure you are logged in as Administrator), the new “Things” field will be added to the list of custom fields for News Items:

sitefinity-custom-fields 

And either creating or editing a news item will reveal the custom selector field control, allowing you to easily assign custom items to your news content.

Wrapping Up

By leveraging the Sitefinity API, you can easily expand the native Sitefinity modules to include links to custom content types from the Module Builder. Using the provided code you should be able to add custom fields of any type, and automatically place them in the backend create and edit forms for immediate use.

The following two tabs change content below.

selaromdotnet

Senior Developer at iD Tech
Josh loves all things Microsoft and Windows, and develops solutions for Web, Desktop and Mobile using the .NET Framework, Azure, UWP and everything else in the Microsoft Stack. His other passion is music, and in his spare time Josh spins and produces electronic music under the name DJ SelArom. His other passion is music, and in his spare time Josh spins and produces electronic music under the name DJ SelArom.