Thursday, November 17, 2016

A useful customization of Sitecore Multilist with search field.

Once upon a time I came across a requirement to display the item field along with the item name in Sitecore multilist with search field. 
Many times multilist with search field shows duplicate item names, because there are items which are slimier in display name but different in the field values. This post is about displaying the difference inside the control itself.
The multilist with search is a very useful and powerful field which runs on javascript and it uses the Sitecore search functionality.
This is how the multilist with search looks like in Sitecore 8.2 : 
These three Notice items, you are viewing inside multilist are coming from a field source string which looks like this:
StartSearchLocation={AB19F622-7FB9-42EC-BC9F-A0E5824EBF1F}&Filter=+_path:ab19f6227fb942ecbc9fa0e5824ebf1f|_templatename:Notice

The source items are Notice items having a field "TitleOrName"

What I wanted was a customization to have a field appended to item name:
You can see how TitleOrName field is coming appended to the item's Display names.
And I wanted this to be appended dynamically through field source like this:
StartSearchLocation={AB19F622-7FB9-42EC-BC9F-A0E5824EBF1F}&Filter=+_path:ab19f6227fb942ecbc9fa0e5824ebf1f|_templatename:Notice|_fieldToAppend=TitleOrName
The  _fieldToAppend parameter decides which field is to be  appended to the item display name.
The solution is a custome control, has four parts 
1. Overriding the BucketList class.
2. Fetching the field in the BucketList.js file.
3. Config Changes 
4. Core Database changes

First I decoded the Kernel with refelector and ILSpy and found the BucketList class in  Sitecore.Buckets.FieldTypes.
Override this class in your project assembly. Following is the code:


namespace Sitecore.Buckets.FieldTypes
{
    public class CustomisedMWS : BucketList
    {
        string fieldToAppend = "";
        public override string OutputString(Item item)
        {//Overriding so that selected items can be seen as modified
             fieldToAppend = getFieldToAppend();
            string fieldValueToAppend = "";
            if (fieldToAppend != "")
                fieldValueToAppend = item.Fields[fieldToAppend].ToString();
            Item parentBucketItemOrParent = item.GetParentBucketItemOrParent();
            string arg = (parentBucketItemOrParent != null) ? (" - " + parentBucketItemOrParent.DisplayName) : string.Empty;
            return string.Format("{0} ({1}{2})", item.DisplayName +"-"+ fieldValueToAppend, item.TemplateName, arg);
        }
        
        protected override string ScriptParameters
        {// Overriding to supply the appended field parameter to javascript
            get
            {
                 fieldToAppend = getFieldToAppend();
                return string.Format("'{0}'", string.Join("', '", new object[]
                {
                    this.ID,
                    this.ClientID,
                    base.PageNumber,
                    "/sitecore/shell/Applications/Buckets/Services/Search.ashx",
                    base.Filter,
                    SearchHelper.GetDatabaseUrlParameter("&"),
                    base.TypeHereToSearch,
                    this.Of,
                    base.EnableSetNewStartLocation,
                    this.fieldToAppend
                }));
            }
        }
        private string getFieldToAppend()
        {// This method finds the field inside the source string and returns  
            if (base.Source.LastIndexOf("_fieldToAppend=") > 0)
                return base.Source.Substring(base.Source.LastIndexOf("_fieldToAppend=") + 15);
            else
                return "undefined";
        }
    }
}

Next create a condition in BucketList.js file which identifies whether the call is coming from regular mulilist or the custom multilist.
In case of custom multilist the item fields are required to be fetched from inside the Javascript code. The Sitecore Web API is a great way to fetch the item data asynchronously, see here how I used the RESTfulAPI Item service:

 for (i = 0; i < reducedItems.length; i++) {
                            item = reducedItems[i];
                            if ((fieldToAppend == undefined) || (fieldToAppend == "undefined"))
                            {
                                multilist.options[multilist.options.length] = new Option((item.DisplayName || item.Name) + ' (' + item.TemplateName + (item.Bucket && (' - ' + item.Bucket)) + ')', item.ItemId);
                            }
                            else
                            {
                                var fieldValueToAppend='Unpublished Value.'
                                var _itemName = '';
                                var _templateName = '';
                                var _itemId = '';
                                var xhr = new XMLHttpRequest();
                                xhr.open("GET", "http://blackrock/sitecore/api/ssc/item/"+item.ItemId);
                                xhr.onreadystatechange = function () {
                                    if (this.readyState == 4) {
                                        var jsonobj = JSON.parse(this.responseText);
                                        fieldValueToAppend = jsonobj[fieldToAppend];
                                        _itemName= jsonobj["ItemName"];
                                        _templateName = jsonobj["TemplateName"];
                                        _itemId = jsonobj["ItemID"];
                                        multilist.options[multilist.options.length] = new Option(_itemName + '-' + fieldValueToAppend + ' (' + _templateName + (item.Bucket && (' - ' + item.Bucket)) + ')', _itemId);
                                    }
                                };
                                xhr.send(null);
                            }
                           }

I am not an expert in writing JavaScript so this code is easy to understand.

Last two are pretty minor changes, which are to be done when you are making any custom control. Add a config entry to  Sitecore>ControlSources    .
And add a field type in /sitecore/system/Field types/List Types in core database. Use this field type with your bucket and specify the _fieldToAppend parameter in the source. Result: 

Feel free to use this custom control in your solution.!

No comments: