Part 4: Create a Dropdown Search Refiner Control

November 01, 2013

In this blog post part of the search refiner control series, I'll show how to create a dropdown search refiner control. To make it a bit special, I've added the functionality of showing the filters that were available before the results were refined.



Note: for this post I start with the file I created in part 2 of this series. Download the template here: Custom Search Refiner Control Part 2.

Creating a Dropdown Menu

Creating a dropdown menu for your Search Refiner Control is really simple. The first thing to do is creating the select elements in html, to do this the mark-up of the control needs some modification. For this refiner template I'm going to work with only one dropdown element instead of two (unselected and selected array).

The mark-up is changed to this:

As you can see, I changed the previous DIV elements to select elements. Another thing I've done is, I moved the Remove refinement link out of the select element.

The next step is to change is the ShowRefiner function. In that function the hyperlinks need to be changed to option elements.

This results in the following output:

Dropdown Refiner

Dropdown Refiner

Dropdown Refiner Values

Dropdown Refiner Values

Remove Refinement

Remove Refinement

As you can see, creating a custom dropdown refiner control isn't that hard once you know what need to be updated. Now we go a step further, showing the elements that were there before the refining.

Showing the Unselected Refiners

Once you refined your results, the unselected refiners array will be empty. This is due to the fact that the selected array will be populated once the result set is refined. The selected array contains the possible refiners once refined.

It isn't possible to retrieve the old (unselected) refinement values from the current ListData object, because it doesn't contain these values anymore. It now has the refiner values for the new / refined set of results.

The approach to show the unselected values, is the same that I've used to create the load more results button for the CSWP (if you didn't read this post, here is the link to it: Create a Load More Results Link / Button for the Content Search Web Part (Display Template)).

The explained approach in that post is to store the results in a container outside the render area of the current display template. If they are stored inside the render area of that display template control, they'll be removed once the control is refreshes (happens each time you refine).

Note: the following piece of code can be written with jQuery in a "cleaner" and quicker way.

The first thing you'll need is a hidden container that is used to temporally store the refiner option.

With this code a new block gets created in the refinement panel right after the search refiner control blocks, I gave it a unique ID to easily retrieve it.

HTML Mark-up

HTML Mark-up

The next step is to change the ShowRefiner function to populate the hidden block with the refiners. This is only needed for the unselected list of refiners, so we can add a check to see if the results aren't refined.

If you test this now, you won't see anything visual, but if you check the hidden container, you'll see that it gets populated with the refiners.

Hidden Container with Refinement Values

Hidden Container with Refinement Values

This list needs some clean up every time the template starts populating the unselected array. If you wouldn't do it, you'll end up with double items. To achieve this, I created a ClearHiddenList function that will be called each time before the unselected loop starts the enumerations.

As I said, the function call will be done just before the unselected array loop. I also added a check to see if unselected array contains items, otherwise the hidden block would be erased after every refresh.

Almost there, we just need to append some extra bocks / containers to append the hidden refiners back to the dropdown. For this I'll use two option grouping optgroup blocks, these blocks get their own IDs.

The mark-up of these optgroup blocks look like this:

Note: for the visual part, I changed the order form the loops. I've placed the selected loop above the unselected one.

Right now the result looks like this once you refine your results:

Dropdown with Refinement Groups

Dropdown with Refinement Groups

Adding the Hidden Refiners to the Dropdown

To append the hidden refiners to the dropdown, we need to implement a callback function that populate the hidden refiners once the refiner controlled finished rendering.

This can be achieved by using the AddPostRenderCallback function.

If you now do a search and refine the results, you will see that the hidden refiners are added to the dropdown.

Dropdown with Refinement Groups and Values

Dropdown with Refinement Groups and Values

If you want to use one of the other refiners, you'll need to change the method that is used for refining the results. We cannot use the addRefinementFiltersJSON, we should use the updateRefinersJSON method instead. This is because the refinement that is in place needs to be updated, instead of adding an extra refinement.

The ShowRefiner function call in the unselected loop should be changed to this:

One last thing is to don't populate the selected option to the unselected list. To check this we need to add a check in the AddPostRenderCallback function to check if the element is in the selected list.

The outcome looks as follows:

Dropdown with Refinement Values (no duplicates)

Dropdown with Refinement Values (no duplicates)

Set the Selected Item

One last thing that needs to be done, is to set the selected item in the dropdown. This can be achieved by adding a Boolean value to the ShowRefiner function call, so that this value can be used to create a selected option once this value is true. The updated ShowRefiner function looks like this:

The function call in the selected loop needs to be updated to set the value to true, and the two other calls (unselected loop, and removal link) need to be set to false.

Selected Refiner

Selected Refiner

This was the last step for this post.


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

Part 5

In the next part of this series I'll explain the methods that can be used for refining your results. Currently we have used a few of them, but I didn't explain how they work and what they do. These things will be tackled in the part 5.



Andy pointed out that the onclick event doesn't work on dropdown options in Google Chrome. I have modified the code to now support Google Chrome. For this I changed all the onclick attributes to value attributes, and set an onchange attribute on the select element.

Blog posts in this series: