+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

How to Create a MultiPage Field Control in Sitefinity

by Zheyna Peleva
Most of you have already used Sitefinity's out-of-the-box PageField control, allowing you to select pages from the SiteMap in content modules. In this blog post I'm going to show you how to create your own custom MultiPage field control, that can be used to select multiple pages in Sitefinity CMS. I'm not going to cover the basics of the process for creation of field controls. We already have documentation on this. You might want to check it here.

In my example I've used a sample field control, generated by Sitefinity Thunder. As you know, we have the template for the field control, which contains all controls, that will appear in the backend, once you add the custom field control to a module. The most important part of the template is the FlatSelector, which will handle the logic for selecting items from particular content type - in our case Pages. We pass the PageService URL to the ServiceUrl property of the FlatSelector. In the DataMemberInfo we specify the value what property of the content type will appear in the selector - we choose Title, to be able to select pages by Title. One important FlatSelector property is AllowMultipleSelection. When it is set to True you will be able to select multiple items, and if it is False, it will become a single item selector again.

<sitefinity:FlatSelector ID="pageSelector" runat="server" ItemType="Telerik.Sitefinity.Pages.Model.PageNode"
        DataKeyNames="Id" ShowSelectedFilter="false" AllowPaging="false" PageSize="10" BindOnLoad="true"
        AllowSearching="true" ShowProvidersList="true" InclueAllProvidersOption="false"
        SearchBoxTitleText="Filter by Title" ShowHeader="true" AllowMultipleSelection="true"
        ServiceUrl="~/Sitefinity/Services/Pages/PagesService.svc/"  >
        <DataMembers>
            <sitefinity:DataMemberInfo ID="DataMemberInfoSelectedPage" runat="server" Name="Title" IsExtendedSearchField="true" HeaderText="Title">
                    <span>{{Title.Value}}</span>
            </sitefinity:DataMemberInfo>
        </DataMembers>
    </sitefinity:FlatSelector>

In the MultiPageSelector.cs we get all controls from the template and pass them to the javascript as Element or Component properties, respectively.

public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
       {
           List<ScriptDescriptor> descriptors = new List<ScriptDescriptor>();
 
           ScriptControlDescriptor descriptor = base.GetScriptDescriptors().Last() as ScriptControlDescriptor;
 
           descriptor.AddElementProperty("selectButton", this.SelectButton.ClientID);
           descriptor.AddElementProperty("lnkDone", this.DoneButton.ClientID);
           descriptor.AddElementProperty("lnkCancel", this.CancelButton.ClientID);
           descriptor.AddComponentProperty("pageSelector", this.PageSelector.ClientID);
 
           descriptors.Add(descriptor);
 
           return descriptors.ToArray();
       }

Most of our logic is in the javascript, so let's get to it. The js file contains the get_value and set_value properties, as well as get and set for: the page selector, the selection button, the Done and Cancel buttons. Notice we have two additional properties get_uiCulture and set_uiCulture. The get property returns the current UiCulture. In the set property we set the UiCulture to our PageSelector and we also set the itemsFilter property of your field control to the following filterExpression: "AvailableLanguages.Contains(\"" + culture + "\")". This way we make sure that, depending on the current culture, the selector will return only items that have such language translations. It is also important to implement the ILocalizableFieldControl interface in the javascript to use the multi language support.
The following part of the code adds a button click handler to each button:
if (this._selectButton) {
            this._selectButtonClickDelegate = Function.createDelegate(this, this._selectButtonClicked);
            $addHandler(this._selectButton, "click", this._selectButtonClickDelegate);
        }
 
        if (this._lnkDone) {
            this._PagesDoneSelectingDelegate = Function.createDelegate(this, this._PagesDoneSelecting);
            $addHandler(this._lnkDone, "click", this._PagesDoneSelectingDelegate);
        }
 
        if (this._lnkCancel) {
            this._PagesCancelDelegate = Function.createDelegate(this, this._PagesSelectorCloseHandler);
            $addHandler(this._lnkCancel, "click", this._PagesCancelDelegate);
        }

Take a look at the _selectButtonClicked function, where after opening the Page selector dialog we pass the ItemsFilter to the page selector again, so that it will display the selected value in the current language.
_selectButtonClicked: function (sender, args) {
       debugger;
       this._selectPagesDialog.dialog("open");
       this._dialogScrollToTop(this._selectPagesDialog);
       this.get_pageSelector().set_itemsFilter(this._itemsFilter);
       this.get_pageSelector().set_selectedKeys(this._value);
       this.get_pageSelector().dataBind();
       return false;
   },

Also, let's look at the _PagesDoneSelecting. When we are done selecting pages, we get their ids and populate the "VALUE" of the field control with the selection. We save an array of ids, that is why the field in the dynamic module must be of type Array of Guid.

_PagesDoneSelecting: function (sender, args) {
       this._selectPagesDialog.dialog("close");
      
       var arr = new Array();
       var selectedPages = this.get_pageSelector().get_selectedItems();
       for (var i = 0; i < selectedPages.length; i++) {
           arr.push(selectedPages[i].Id);
       }
       //SET THE VALUE
       this._value = arr;
 
       this._setSelectedItemsLabel(arr.length);
       return false;
   },

I believe we covered the essential parts of the field control implementation. In the video below you will see how to add it to your modules. Don't forget that the type of the property you'll add to your modules should be Array of Guids.



This field control can practically work with dynamic types, as well (after slight modifications). This can be done by changing the serviceUrl of the FlatSelector to the url of DynamicModule services.

Hope you like the blog post!

3 comments

Leave a comment
  1. Stephen Reynolds Jun 06, 2013
    How do you add a "remove pages" button simulator to the category selector
  2. Joel Jun 15, 2013
    Could we see the complete source for the field selectors, I don't quite understand where the buttons are coming from... Perhaps a zip of the whole component?
  3. Kamran Apr 10, 2014

    What i need is a single page selector [which will use GUID type instead of array of GUID]. I am using sitefinity version 6.3. Can u please make another version of it for single page selection @ZHEYNA PELEVA

    Leave a comment