Part 2: Adding Refinement Actions to the Custom Search Refiner Control

October 23, 2013

In the previous post I explained how to create your first search refiner control template. The template that was created wasn’t that useful, because it missed the refinement actions. In this post I explain how to add these refinement actions to your template and what to do once results are refined.

Note: For this post I’m going to use that display template as the starting point for this post. Here you can download it directly: Custom Search Refiner Control.

Adding Refinement Actions

There are a couple of ways to add refinement actions and they depend on the structure they is used. In this post I’m going to create them as hyperlinks. To start, the ShowRefiner function needs to be modified to create these hyperlinks, the code looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!--#_
function ShowRefiner(refinementName, refinementCount, refiners, method) {
  // Create the onClick event
  var onClickEvent = "$getClientControl(this)." + method + "('" + $scriptEncode(Sys.Serialization.JavaScriptSerializer.serialize(refiners)) + "');";
  // Check if the refinement contains results
  if (refinementCount != null) {
_#-->
     <div><a href='javascript:{}' onclick='_#= onClickEvent =#_'>_#= $htmlEncode(refinementName) =#_ (_#= refinementCount =#_)</a></div>
<!--#_
  }
}
_#-->

As you can see in the code, the method to add these refiners is the addRefinementFiltersJSON, which as the name suggests adds the refinement to the results.

Note: I’ll explain these method in part 5 of this blog series.

To make use of the updated ShowRefiner function, you’ll need to add some parameters to the function call (the refiner tokens that are used to do the refinement of the results, and the refinement method that needs to be executed):

1
ShowRefiner(filter.RefinementName, filter.RefinementCount, refiners, 'addRefinementFiltersJSON');

The function will now create hyperlinks. Once you click on one of these links, the onclick event triggers the results to refine. The HTML mark-up of the links looks like this:

1
<a onclick="$getClientControl(this).addRefinementFiltersJSON('{\u0022Brand\u0022:[\u0022\\\u0022\u01C2\u01C2436f6e746f736f\\\u0022\u0022]}');" href="javascript:{}">Contoso (135)</a>
Brand Refiner with Refinement Actions
Brand Refiner with Refinement Actions

Reset the Current Refinement

Now that the hyperlinks are in place, it’s possible to refine the search results, but once you do this, you’ll end up with an empty refinement control.

Empty Refiner
Empty Refiner

The next thing to do is to show a hyperlink to reset the current refinement.

For this you’ll need a new HTML block that becomes visible once the results are refined. This can be achieved by checking the following things:

  • Check if the selected array contains values (selectedFilter):
1
selectedFilters.length > 0
  • OR - Check if there’re refinement tokens in use for the current search refiner control:
1
2
3
var currentRefinementCategory = ctx.ClientControl.getCurrentRefinementCategory(ctx.RefinementControl.propertyName);
// Check if the object is null or undefined && Count the tokens currently in place
var hasAnyFiltertokens = (!Srch.U.n(currentRefinementCategory) && currentRefinementCategory.get_tokenCount() > 0);

The statement looks like this:

1
2
3
4
5
6
7
8
9
if (selectedFilters.length > 0 '' hasAnyFiltertokens) {
_#-->
  <div id='SelectedSection'>
<!--#_

_#-->
  </div>
<!--#_
}

Now let’s add a hyperlink to remove the current refinement. To remove the current refinement, the updateRefinersJSON method will be used. You also have a removeRefinementFiltersJSON method, but this needs the exact refinement token that needs to be removed. The approach with the updateRefinersJSON method is to give a null value to the refinement.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
if (selectedFilters.length > 0 && hasAnyFiltertokens) {
_#-->
  <div id='SelectedSection' class='ms-ref-selSec'>
<!--#_
    var refinerRemoval = new Object();
    // Set a null value to remove the current refining
    refinerRemoval[ctx.RefinementControl.propertyName] = null;
    ShowRefiner('Remove refinement', null, refinerRemoval, 'updateRefinersJSON');
_#-->
  </div>
<!--#_
}

The last thing to do is to do a small modification to the ShowRefiner function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!--#_
function ShowRefiner(refinementName, refinementCount, refiners, method) {
  // Create the onClick event
  var onClickEvent = "$getClientControl(this)." + method + "('" + $scriptEncode(Sys.Serialization.JavaScriptSerializer.serialize(refiners)) + "');";
  // Check if the refinement contains results
  if (refinementCount != null) {
_#-->
     <div><a href='javascript:{}' onclick='_#= onClickEvent =#_'>_#= $htmlEncode(refinementName) =#_ (_#= refinementCount =#_)</a></div>
<!--#_
  } else {
_#-->
    <div><a href='javascript:{}' onclick='_#= onClickEvent =#_'>_#= $htmlEncode(refinementName) =#_</a></div>
<!--#_
  }
}
_#-->

This will result in the following output:

Remove refinement link
Remove refinement link

Show the Selected Refinement

The same approach as the unselected loop will be done. The only difference is that you need to enumerate the selectedFilters array, and in this loop the removeRefinementFiltersJSON method can be used because you know the exact tokens.

1
2
3
4
5
6
7
8
for (var i = 0; i < selectedFilters.length; i++) {
  var filter = selectedFilters[i];
  if(!$isNull(filter)) {
    var refiners = new Object();
    refiners[filter.RefinerName] = filter.RefinementTokens;
    ShowRefiner('Remove ' + filter.RefinementName, filter.RefinementCount, refiners, 'removeRefinementFiltersJSON');
  }
}

This script results in the following output when you’re going to refine the results.

Refinement Example 1
Refinement Example 1
Refinement Example 2
Refinement Example 2

Download

Download the complete search refiner control here: Custom Search Refiner Control Part 2.

Part 3: File Type Refinement

Right now we created a fully functional display template that can be used to set an unset the refinement. This template works with every search data type, but there is own data type that need special attentions. This is the FileType search data. In the next post I’ll describe to which things you need to pay special attention to when you want to use the FileType search data type.

Blog posts in this series:

Comments

comments powered by Disqus