AlertThis post is over a year old, some of this information may be out of date.
How to add multi-sorting of managed properties in your display templates
post
Last week I had an internal event where I did one of my new sessions: take your display template skills to the next level. One of the topics that I discuss during this session is how you can add sorting in your display templates.
During my talk someone asked if it is possible to sort the results on multiple managed properties. Currently I only did it for one managed property at a time.
As it turns out it is possible, but you need to include some extra JavaScript. In this post I will explain how you can achieve sorting of search results on multiple managed properties.
How to add multi-sorting
If you want to add sorting possibilities into your display templates, you first need to register the sorting options to the available sorts array of your data provider. This is explained in my first post: how to add sorting in display templates.
The code for registering your sorts looks like this:
To do the sorting of your results, you will have to include a trigger that uses one of the registered sorting options. The following methods are available to trigger the sorting: sort or sortOrRank. These methods can be used like this:
Now the problem is if you have multiple links on your page for managed property sorting (this could be the case if you are using my table layout display template), you will only be able to sort on one managed property at a time. If you click on another managed property to sort on, the previous one will get overridden.
Example: if you first so a sorting on the file size, the results get sorted on the file size. If you click on the author sorting links, the sorting on size is overridden by the author sorting.
The reason for this behavior is because a new query gets executed behind the scenes without taking the previous sorting into account.
Here is a code snippet of what is happening behind the scenes in the Search.ClientControls.js file:
// Get the available sorts on the data provider
varsorts=dataProvider.get_availableSorts();if(!Srch.U.n(sorts)&&sorts.length>0){for(vari=0;i<sorts.length;i++){varsort=sorts[i];// Find the triggered sort, once found, do a new query
if(!Srch.U.n(sort)&&sort.name===sortName){varqueryState=newSrch.QueryState();queryState.o=sort.sorts;...queryState.s=1;varqueryEvent=newSrch.QueryEventArgs(queryState);queryEvent.userAction=4;this.raiseQueryReadyEvent(queryEvent);return;}}}
So if you want to include multi-sorting functionality to your display template, the only option you have is to write JavaScript code to enable this.
functionsortProperty(sortName,clientControl){if(Srch.U.e(sortName)){return;}vardataProvider=clientControl.get_dataProvider();if(Srch.U.n(dataProvider)){return;}// Retrieve the available sorts
varavailableSorts=dataProvider.get_availableSorts();// Retrieve the current sorts
varcurrentSorts=clientControl.get_dataProvider().get_currentQueryState().o;if(!Srch.U.n(availableSorts)&&availableSorts.length>0){vartriggeredSort;// Loop over each of the available sortings
for(vari=0;i<availableSorts.length;i++){varsort=availableSorts[i];// Check if the sorting has been selected
if(!Srch.U.n(sort)&&sort.name===sortName){// Store the current sorting
triggeredSort=sort.sorts;}}varsortarray=[];varprocessed=false;// Check if there was already sorting in place
if(!Srch.U.n(currentSorts)&¤tSorts.length>0){// Loop over the current sorts
for(vari=0;i<currentSorts.length;i++){varcurrentSort=currentSorts[i];// Check if the current sort is equal to the clicked sort
if(currentSort.p===triggeredSort[0].p){// Push the new sorting option on the array
sortarray.push(triggeredSort[0]);processed=true;}else{// Push the unchanged sort on the array
varsortObj={p:currentSort.p,d:currentSort.d};sortarray.push(sortObj);}}// Check if the clicked sorting was processed.
// If it is not processed, push it on the array.
if(!processed){sortarray.push(triggeredSort[0]);}}else{// If the results were not yet sorted, use the clicked sort option
sortarray=triggeredSort;}// Do a new query with the sort information
varqueryState=newSrch.QueryState();queryState.o=sortarray;queryState.s=1;varqueryEvent=newSrch.QueryEventArgs(queryState);queryEvent.userAction=4;clientControl.raiseQueryReadyEvent(queryEvent);return;}}
Note: the function expects the name that is specified in the available sorts array (in the code snippet above this is Created-ASC or Created-DES) and the current client control.
The code checks if a sorting is in place, and if that is the case, it will retain the sorting order and add or update the triggered managed property sorting.
Now if you have multi-sorting enabled in your display template, it can be useful to remove a specific sorting. For example: if you did a sort on Author and this didn’t gave you the results you expected, by triggering a sorting removal the author sorting gets unset.
Here is a function I created to achieve the removal functionality:
functionremoveSortProperty(property,clientControl){if(Srch.U.e(property)){return;}vardataProvider=clientControl.get_dataProvider();if(Srch.U.n(dataProvider)){return;}// Retrieve the current sorts
varcurrentSorts=clientControl.get_dataProvider().get_currentQueryState().o;// Check if the results are already sorted, otherwise the property cannot be removed
if(!Srch.U.n(currentSorts)&¤tSorts.length>0){varsortarray=[];varprocessed=false;// Loop over the current sorts
for(vari=0;i<currentSorts.length;i++){varcurrentSort=currentSorts[i];// Check if the current sort is equal to the clicked sort
if(currentSort.p!==property){// Push the unchanged sort on the array
varsortObj={p:currentSort.p,d:currentSort.d};sortarray.push(sortObj);}else{processed=true;}}// Check if the sort option was removed from the sorting array
if(processed){// Do a new query with the sort information
varqueryState=newSrch.QueryState();queryState.o=sortarray;queryState.s=1;varqueryEvent=newSrch.QueryEventArgs(queryState);queryEvent.userAction=4;clientControl.raiseQueryReadyEvent(queryEvent);return;}}}
Note: this function expects the property name that needs to be removed and the current client control.
I have created a new “updated” version of the table layout display template to include this functionality. In the new template you can do multi-sorting and removing the set sorting.