SharePoint 2013 Refiner Multi-Value (‘Contains’ instead of an ‘Equals’)

You are in a situation where your Managed Property contains multiple values (e.g. you programmatically populate a Property Bag, which is added to the IndexedPropertyKeys and then exposed as a Managed Property). You add a Content Search Web Part on your page and also a refiner. In the Refiner panel you add your managed property and you are horrified by the following end result:

1

If you are reading this page you already know that such rendering causes a problem – the entries within the multi-value field are not ‘normalized’ to single entries, hence, you now can’t search only for items that have a property which contains only (e.g.) one of the values. You have already probably tried setting the ‘multi-value’ property of the Managed Property, but alas, no success.

Fear not, for I have a solution! It is delivered as a custom Refiner filter, which is based on the Filter_MultiValue.html OOB Refiner filter. Here it is: click here.

How to use it? Simple:

1. Drop the file into your Filters folder (Site Collection -> Settings -> Master pages and page layouts -> Display Templates -> Filters)

2. Make sure you Save, Check In and Publish the file

3. Go to your refiner and edit the web part properties -> Choose refiners

4. Select the newly added Filter

2

5. Ok -> Save page

And the result now is:

3

Much better! Selecting a refiner value and applying actually works too 🙂

4

For the curious, how does the custom Filter work? Well:

1. We set the var useContains = true; Although in my experience it has no effect on the end result

2. More importantly, we add one more for(;;) cycle in the code, which splits every filter item into separate filters:

5

So, instead of having:

[ ] Value 1, Value 2, Value 3, …

you will have:

[ ] Value 1

[ ] Value 2

[ ] Value 3

3. But MOST IMPORTANTLY, instead of hex-ing the refiner token, as the OOB filter does, we use the plain-text value:

6

This is crucial! Without this part the refiner will not work as expected.

So let’s compare an original query URL generated by the OOB Filter_MultiValue.html with the custom Filter_Contains_MultiValue.html.

Before:

#Default=
{
“k”:””,
“r”:[{
“n”:”HahnAirPMOProjectManagerDisplayValue”,
“t”:[“\”ǂǂ4c41425c41646d696e6973747261746f72\””],
“o”:”OR”,
“k”:false,
“m”:{“\”ǂǂ4c41425c41646d696e6973747261746f72\””:”LAB\\Administrator”}}]}

After:

Default=
{
“k”:””,
“r”:[{
“n”:”HahnAirPMOProjectManagerDisplayValue”,
“t”:[“LAB\\Administrator”],
“o”:”OR”,
“k”:false,
“m”:{“LAB\\Administrator”:”LAB\\Administrator“}
}]
}

That specific part seems to cause SharePoint to do ‘contains’ search, instead of an ‘equals’ search.

Hope this helps!

PS

Don’t forget to set your ‘delimiter’ variable to whatever string you use for separating the values within the field. It is currently set to ‘, ‘ (coma and space).

Update 1:

I have updated the source code to handle strings with backslash in them differently. i.e.:

– If the string has a backslash (e.g. ‘domain\admin’) – don’t put it withing brackets

– if the string has no backslash (e.g. ‘Farm Admin’) – put it in brackets, otherwise the KQL is invalid and causes an error

Advertisements

24 Responses to SharePoint 2013 Refiner Multi-Value (‘Contains’ instead of an ‘Equals’)

  1. Michael says:

    Thank you for this solution! It spared me from creating a really ugly workaround for using a lookup field that points to a multichoice field as search refinement.

  2. Steve says:

    Thanks for this article. How do I sort the values alphabetically after delimiting the values?

  3. SR_tqlone says:

    Thank you so much! You saved my day and the following weeks, too 🙂

  4. MDM says:

    Great article an thank you so much to share your code !

  5. martusha says:

    Super cool! Thanks!

  6. Hans says:

    Great article! I only have one problem with the code. My keywords in SharePoint 2013 are separated by a “;” instead of a “,”. Is there any possibility to change the script so that it does work with this as well?

    • hyankov says:

      Hi and thank you.

      Please note the following paragraph in the article:

      Don’t forget to set your ‘delimiter’ variable to whatever string you use for separating the values within the field. It is currently set to ‘, ‘ (coma and space).

  7. Jason says:

    Hi,
    The link to your custom filter no longer works (http://1drv.ms/1qSrLuQ). Would you have a mirror to the file?
    Thanks!

  8. Paul says:

    GREAT Article! How do you set it up so that it is links on for the refiner as opposed to the multi-select check boxes?

    • hyankov says:

      Hi,

      I think you’d have to modify Filter_MultiValue_Body.html – as the title says it is responsible for rendering the ‘body’ of the refiner (while the one discussed in this article only controls the logic for separation of the items)

      • Paul says:

        Thanks, found it. Make a copy of Filter_MultiValue_Body.html and update the links in your “main” file to point to the generated js. Very good article again. Thanks!

    • Mark Cooley says:

      Hi Paul

      Are you able to share your modified copy of Filter_MultiValue_Body.html. I am wanting to achieve the same thing, but don’t have sufficient knowledge to make the required changes

  9. Arun Kumar says:

    Great Article!

    Have enabled “ShowCounts” options as “true” and with some modifications for the code to get the refiners count matching to search results count.

    if(!hasNoListData) {
    for (var i = 0; i < listData.length; i++) {
    var filter = listData[i];
    if(!$isNull(filter)) {

    var originalRefinementName = filter.RefinementName.split(delimiter);
    for (var j = 0; j -1) ? originalRefinementName[j] : ‘”‘ + originalRefinementName[j] + ‘”‘;
    if (typeof listDataTokenToDisplayMap[refinementToken] == ‘undefined’) {
    listDataTokenToDisplayMap[refinementToken] = originalRefinementName[j];
    listDataTokenToCountMap[refinementToken] = filter.RefinementCount;
    if(!hasAnyFilterTokens && !$isEmptyString(originalRefinementName[j]) && !$isEmptyString(refinementToken)) {
    refiners.push(
    {
    RefinementName: originalRefinementName[j],
    RefinementToken: refinementToken,
    RefinementCount: filter.RefinementCount,
    IsSelected: false
    });
    }
    }
    else
    {
    refiners.map(function (filterItem) {
    if (filterItem.RefinementName == originalRefinementName[j]) {
    filterItem.RefinementCount = +filterItem.RefinementCount + +filter.RefinementCount;
    }
    });
    }
    }

    }
    }
    }

    This works perfectly fine before applying filters, but after applying any filter there is count mismatch between refiners count and search results count. Can you please help me in resolving the same.

    • Evelyn says:

      Hi! I modified my version of the code, now it’s working with setting ShowCount = true. It work’s perfect for initializing and after refining other refiners. I could send you a copy of my file.

      • Sooraj says:

        Could you please send a copy of this where showcount works before and after applying filter?

  10. Soul Rider says:

    I was trying to recreate the file from the code you posted, as OneDrive is blocked here at work. I have managed to get the filter to work and display the individual refinement elements from the column, however, when I select an option and click apply, I get an error advising –

    Property doesn’t exist or is used in a manner inconsistent with schema settings.
    Correlation ID: ba269f9d-4a0b-0057-0c7a-7d441f889306

    Could you post the code in full on the site at all? So I can see where I went wrong in my attempt to replicate it 🙂

  11. Deepak Jethani says:

    Hi the refiners are not appearing in alphabetical order, how can we do that ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: