Azure / Office 365 / SharePoint Development / Search

Part 5: The Search Refiner Control Methods Explained

on Nov 06, 2013 by Elio Struyf with 46 comments

In previous posts I showed you how you to build your own Search Control Refiners. This post will focus on the JavaScript methods that can be used for refinement. There are a couple of them, but when do you need to use which refiner method? I'll split this post up in sections to describe the actions that can be achieved.

JSON URL

In SharePoint 2013 you can accomplish almost everything with just some REST calls. This isn't that different when working with search. The search web parts make use of a JSON formatted string in the URL to do the search and refinements. This can easily be checked by going to a search center perform a search and do some refinement. You'll end up with a URL like this:

I did the following actions:

  1. Did a search on custom refiner;
  2. Refined the results on word and myself;

That gave me that URL.

JSON Break Down

  • k: keyword;
  • r: refinement filter;
    • n: refiner name;
    • t: refiner tokens;
    • o: operator (and, or);
    • k: use KQL (Boolean);
    • m: this is the token to display value map. It's used when a custom refinement value (textbox) is used. This stores the value that you inserted, to visualize it in the refiner. Example: "m":{"equals(\"Item Value Text Box\")":"Item Value Text Box"}
Mapping Value

Mapping Value

Note: you can find more information on the fields: QueryState members

Refinement Tokens

Most of the time, you'll see refinement tokens in the URL like this: ǂǂ456c696f20537472757966. This is the refinement value converted to HEX. If you are going to decode this from HEX to ASCII, you'll get Elio Struyf. You can also use the refinement values themselves. As you can see in the URL above, the FileType refiner uses the refinement values, instead of the tokens.

Adding Refinement Filters

When you want to add refinement to the results, you have a couple of options:

  • addRefinementFilter: expects the filter name and filter token / value;
  • addRefinementFilters: this method expects a refiner object;
  • addRefinementFiltersWithOp: this is the method to use to add refinement with operators ('or', 'and').
  • addRefinementFiltersJSON: requires a JSON formatted input ({"Brand":["\\"\u01C2\u01C2426c61636b\\""]});
  • addRefinementFiltersJSONWithOr: (used for adding a multi-value filter – this is used for defining all the content classes for tasks, or defining the Word file extensions);
  • updateRefiners: although the name specifies something else, it can also be used to add refinement. This method requires a refinement object;
  • updateRefinersJSON: the same as the previous, but expects a JSON string.

These methods can be used on the refinement control. To test them, you can open up your browser developer tools (F12) and retrieve the refiner control like this:

I'll show you how to use these refiner methods with a simple example.

addRefinementFilter

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html"],"o":"and","k":false,"m":null}]}

addRefinementFilters

With a single value:

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html"],"o":"and","k":false,"m":null}]}

With a multi-value:

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html","txt"],"o":"and","k":false,"m":null}]}

addRefinementFiltersWithOp

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html","txt"],"o":"or","k":false,"m":null}]}

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html","txt"],"o":"and","k":false,"m":null}]}

addRefinementFiltersJSON

With a multi-value:

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html","txt"],"o":"and","k":false,"m":null}]}

addRefinementFiltersJSONWithOr

With a multi-value:

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html","txt"],"o":"or","k":false,"m":null}]}

updateRefiners

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html"],"o":"and","k":false,"m":null}]}

updateRefinersJSON

URL outcome: {"k":"test","r":[{"n":"FileType","t":["html"],"o":"and","k":false,"m":null}]}

Update Refinement Filters

When you want to update your refiner with another value, you can make use of the following methods:

  • updateRefiners: requires a refiner object;
  • updateRefinersJSON: the same as the previous, but expects a JSON string.

updateRefiners

URL outcome: {"k":"test","r":[{"n":"FileType","t":[" txt"],"o":"and","k":false,"m":null}]}

updateRefinersJSON

URL outcome: {"k":"test","r":[{"n":"FileType","t":[" txt"],"o":"and","k":false,"m":null}]}

Remove Refinement Filters

The next methods that will be explained, are the ones that need to be used for removing the refinement. Removal of the refinement is a bit different than adding or updating refiners. When you want to remove a refinement, it can be that you want to remove a specific refinement and not the whole refinement. Let me clear that out with an example.

When you are refining the results on file type, it can be that you want to refine on two authors. If you want to remove author two from the refinement, you don't want to remove the whole refinement and refine again on the first author. You probably want just to remove that second author.

For this type of refinement removal, you have the remove methods:

  • removeRefinementFilter: requires the refiner name and token to remove;
  • removeRefinementFilters: requires a refiner object;
  • removeRefinementFiltersJSON: requires a JSON formatted refinement input.

Note: the remove methods need to have the exact refinement that is in place, otherwise it won't do anything.

When you want to remove the whole refinement (first and second author), it is easier to use the update methods:

  • updateRefiners
  • updateRefinersJSON

removeRefinementFilter

removeRefinementFiltersJSON

removeRefinementFilters

Single value:

Multi-value:

updateRefiners

updateRefinersJSON

Part 6

In part 6 I'll show you how to create a multi-value refiner.

Blog posts in this series:

Article comments

  • Pingback: Creating Custom Refiner Control Display Templates for SharePoint 2013 - @eliostruyf()

  • Andy

    We were muddling around trying to figure this out ourselves until I searched and found this article. This is exactly what we were wanting to do and finding such a well written and documented explanation nearly made us cry. Thank you so much!

  • Anatoli

    Hi Elio,

    I’ve derived a custom control from ContentBySearchWebPart. Is there a possibility to extend my custom Content Search Web Part (CSWP) with a refiner based on a content type property?

    To explain it in more detail: I’m trying to extend the standard CSWP with a custom refinement, for example as radio button list that is placed right above the search results.

    While searching for information I’ve found your js documentation and thought if it would be possible to achieve this using the js methods?

    Any idea?

    Thanks!

    • Anatoli,

      These functions only work for a refinement control. You could add a refinement web part to the page, and configure it to use your refinement property.

      Regards,
      Elio

      • Anatoli

        Hi Elio,
        Thanks for your answer anyway.

  • Troels

    Thanks for this beautiful and clear explanation. It always makes me happy when I find a no-crap lowdown on a SharePoint topic. For some reason, so many pages about SharePoint just says so little even if the talk is long enough to outgrow a sane patience. But not here, so thank you Elio!

  • Mike

    Hi Elio,
    An excellent series of posts – thank you for that.

    I’m trying to create a refiner that will allow me to refine content based on the initial part of each hit’s Path. I have a multi-site collection web app, but want to present four divisions of the available content. I started by building a refiner that works on the SPSiteURL property but I’ll need to hard-code each of these mappings and with the number of values that match each division this is likely to be too many values for the URL. Ideally I’d want the JSON object in the URL to support a ‘contains’ search operator instead of an ‘equal’. Do you know if this is possible, and if so how we’d go about doing this?

    Thanks

  • alexeyww

    Hi Elio,

    Thank you for sharing your knowledge about display templates.
    Some things I need I’ve managed to find on your site only.

    Could you please help me clarify one moment about Refinement filters:
    As refinement filters use url’s query string to work it seems impossible to have several Refinement panels that utlilize refinement filters on the same page.

    Is it correct?

    • alexeyww,

      Thank you for the feedback.

      You should be able to use multiple refinement web parts on the same page. They work perfectly together. Are you experiencing some problems with it?

      Regards,
      Elio

      • alexeyww

        Elio,
        I did not make myself clear, sorry.

        I ment that I needed to have several groups of search web parts (refinement, search results, search box) on the same page. And each group of search web parts should work independently from another group. I thought that if each group uses the same URL hash “Default” for coordination inside the group it would be problematic to achieve independence. Fortunately it appears that each group of search web parts can use their own URL hash parameter which can be set as web part property “QueryGroupName”.

  • Mahesh Sasidharan

    I found this blog a bit too late.. ;(
    Added all these functions using custom code… Devastated. But still a great blog.
    Does MSDN even have these things covered?

    • Mahesh Sasidharan,

      Thanks.
      At the time I wrote this, no MSDN information was available about this topic and I think this is still the case.

      Regards,
      Elio

  • Sandip

    Hi Elio,

    Thanks for your great post..It’s really helpful.

    I have the same problem as one asked by Mike i.e. I’d want the JSON object in the URL to support a ‘contains’ search operator instead of an ‘equal’. Do you know if this is possible, and if so how we’d go about doing this?

    Thanks,
    Sandip

  • Sharath

    Hi,
    I have made use of Srch.Refinement.getExpanded and able to collapse and expand the refinement panel.
    Here the requirement is by default all the refiners should be in collapsed state. But selecting one refiner and click on Apply button, only that refiner category should be expandable.

    • Sharath,

      To make them by default collapsed, you will need to update the display template and invert the isExpanded logic. By default it does this:

      That should be inverted to:

      For the implementation of the apply button, you will need to write some extra JavaScript to retrieve the exact refinement control, but you could use the Srch.U.collapsibleRefinerTitle show or hide the refinement control was you have done your check.

      Regards,
      Elio

  • Christophe Vandeput

    Elio,

    How can I work with alias instead of RefinableString01 ?
    When I use the alias the filtering works but the values are not checked in the refinementpanel.

    Kind Regards

    Christophe

    • Christophe,

      You would need to select the RefinableString01 as the refiner, instead of the alias. You could rename the refiner control title.

      Regards,
      Elio

  • k: stands for ctx.RefinementControl[“csr_useKQL”]

    • hyankov,

      Thank you for the information. Appreciated.

      Regards,
      Elio

  • Vlad

    Hi,

    What if the managed property value contains two ore more separate words? In my case, I have a site column of type text and the crawled property for that column is mapped to a managed property.
    If i’m trying to construct my Json like this : var refinerValue = {‘MyManagedProperty’:[‘string1 string2’]}, my search results web part throws an error when calling the function ‘addRefinementFilters’ : “Property doesn’t exist or is used in a manner inconsistent with schema settings.”
    The refinement works fine like this: var refinerValue = {‘MyManagedProperty’:[‘string1*’]}
    There are any syntax rules that I have to use?

    Thx, Vlad

    • Hi Vlad,

      You can pass an array as object to the refiner. Here is an example:

      That object can be passed to your refiner control:

      The refinement in the URL will look like this:

      Regards,
      Elio

  • Pingback: SharePoint Cookies()

  • Julian

    FYI. I believe that the ‘k’ variable in the refiner (you say “still searching for the use of this”) is the KQL flag.

    • Elio Struyf

      Julian,

      Still needed to update it. hyankov also mentioned it a couple of months ago.

      Thanks for the info.

      Regards,
      Elio

  • Garry Sinclair

    In Internet Explorer, if too many options are selected in a multi-value refiner (based on a taxonomy field type), the size of the hash in the url gets too long (over 2kb), resulting in a javascipt error (i read this is the hash value limit in IE), and the refiner not working. Have you experienced this, and do you have any suggestions to get around this issue?

    • Elio Struyf

      Garry,

      The problem with the taxonomy fields is that you may not use the auto-created managed property. This auto-created managed property is mapped with the taxonomy ID, that is what is making your URL getting to long.

      Microsoft has also mentioned it on a Technet article, but it is to well hidden. What you best do is create a new managed property or use the auto defined onces and map the ows_column crawled property with it, instead of using the ows_taxId_column crawled property. I have already described the process in another blog post about sorting managed metadata properties: Sorting search results by managed metadata properties. In the solution section you find the process to map the right crawled property. Once you have this, you need to do a full crawl and use the new managed property as your refiner.

      Regards,
      Elio

      • Garry Sinclair

        Hi Elio,

        I’ll give your suggestion a try. Unfortunately, we have quite a large number of taxonomy fields, and it will be a pain to map them all over, and then change the web parts to use the new managed properties as refiners, but if it works, it will be worth the effort!

        Thanks for the quick reply :-)

        Regards, Garry

  • Yogesh Ghare

    Hi Elio,

    I am looking to build a custom refiner from Managed Navigation. The refiner should be build the same way the taxonomy (tree view). I am refering to using Filter_Default.html template to build the tree view refiner.

    I have split the refiner values into arrays and then built the tree object by

    var arrTemp = filter.RefinementName.split(“:”);
    addToTree(Tree,arrTemp);

    var Tree = {};

    function addToTree(tree, array) {
    for (var i = 0, length = array.length; i < length; i++) {
    tree = tree[ array[i] ] = tree[ array[i] ] || {};
    }
    }

    But I am not sure on how to build the UL element and dynamically append the sub nodes to the parent LI (in the OutputFilter function)

    Any reference would be highly appreciated.

    Regards,
    Yogesh

    • Raj

      Hi Yogesh, Did you get any solution for this ? I am also looking for the same requirement.

  • naresh .k

    Can we filter the date range using these methods. I tried $getClientControl(this).updateRefinersJSON(‘{“AstroArticleStartDate”:[“range(2016-05-30T16:00:00.000Z,2016-05-19T16:00:00.000Z)”]}’) but nor working.

    • You can indeed refine on date ranges, check out this post for more information about it: http://www.eliostruyf.com/part-7-working-ranges-search-refiner-control/

      If it doesn’t work, check if the MP is refinable and type set to datetime. You can also check for errors in the browser developer console.

      • naresh .k

        Its working..Great work.. Helped me lot in achieving most of my tasks .. Wonderfull blog.. Keep posting..

  • Dan A

    Hi Elio, great article as always! I had a quick question that I was hoping you could shed some light on. Is there a special syntax or encoding that I need to perform for terms which contains spaces or multiple words?

    For example I am passing “Speciality Companies” but the space between terms blows up my refiner. I tried encoding the strings but that didn’t seem to work either :/. If I remove that term it works perfectly, I just can’t seem to figure out how to use terms which are a phrase or multiple words. Any Ideas?

    var refiner = $getClientControl(document.getElementById(“Refinement”))
    var refinerValue = {‘owstaxIdCNCMainAudience’:[‘Fidelis’, ‘Envolve’, ‘Speciality Companies’]}
    refiner.addRefinementFiltersWithOp(refinerValue, ‘or’)

    Thanks Again!!!
    Dan

    • Dan A

      Well after some trial and error I was able to get this working. I was over thinking it, I simply had to wrap the phrase in double quotes. Hope this helps someone else :).

      var refinerValue = {‘owstaxIdCNCMainAudience’:[‘Fidelis’, ‘Envolve’, ‘”Speciality Companies”‘]}

      Thanks Again,
      Dan

  • Basant Pandey

    Hi Elio,

    Thanks for this great post. I have one question related to the refiners maximum values option. Here is the scenario. I have created the custom refiner typeahead in a refiner, I mapped one custom column with one Managed property and make it to refinable as attribute. The list having 5000 items all are unique and the refiner only showing 1994 items. Can you please why this showing this much count I am expecting more than this. It would be great help me if you have any idea about the search boundaries related to this.

    Thanks Basant

    • How are you doing your call for retrieving the refiners? Is this a typical search query? If so, check that you are retrieving duplicates. Most of the time, this is causing the trouble.

  • Is there any reason why you are updating the query on page load? You can also specify this query in the query builder so that you do not trigger a new query.

    • Iqbal sheikh

      HI Elio,
      In our requirement we are getting path from other resource( path could be different) according to those path need to set refiner and search result dynamically.

      Thanks
      Iqbal

      • Would query string params be an option? This can easily be included in the query.

  • Kevin Murphy-Ferguson

    Hi Elio,
    What a fantastic resource this series of articles is! Can you tell me if a refiner can influence the sort order of the results? I have been changing the sort order of my results by using the “o” parameter that is a sibling of the “k” and the “r” parameters (https://goo.gl/pFuFGQ), but doing that as a custom control that wrote out the whole Url. I would like to stop having to code the whole URL, and instead put my custom sorting logic into a refiner.
    Can a refiner have access or change the “o” parameter in the Url?

    • There is always a way to do it, but by default the refiner methods can only be used for refining/filtering results. You cannot use it for sorting the results. If you want to make it happen, you are going for a similar approach you are already using.