Auto collapse multi-valued refiners in the SharePoint 2013 search refinement panel


My client asked if it was possible to auto-collapse the refinement panel and I thought to myself...  that should be a setting right?  Probably something that I had just never used or needed, it's got to be there. 

No.

So I found this great post that gives some good instruction on how to modify Filter_Default.html to allow single valued refiners to appear collapsed when the page is initially rendered.  Awesome, 1 down.

But this didn't work for multi valued refiners because they use a different template, well... actually 2 templates, Filter_MultiValue.html and Filter_MultiValue_Body.html.  Ok, simple enough, we just have to make some mods to both files.  First, we edit Filter_MultiValue.html to add a line to set its defaulted state to collapsed.

var hasNoListData = ($isEmptyArray(listData));

var propertyName = ctx.RefinementControl.propertyName;

var displayTitle = Srch.Refinement.getRefinementTitle(ctx.RefinementControl);

var isExpanded = Srch.Refinement.getExpanded(ctx.RefinementControl.propertyName);

 becomes

 

var hasNoListData = ($isEmptyArray(listData));

var propertyName = ctx.RefinementControl.propertyName;

var displayTitle = Srch.Refinement.getRefinementTitle(ctx.RefinementControl);

Srch.Refinement.setExpanded(ctx.RefinementControl.propertyName, false);

var isExpanded = Srch.Refinement.getExpanded(ctx.RefinementControl.propertyName);

Now on to Filter_MultiValue_Body.html, and before I go much further, I’ve found what I consider a bug but generally, it would never be noticed  because the default state for any refiner is expanded.

 

Notice in Filter_MultiValue.html the line

 

var isExpanded = Srch.Refinement.getExpanded(ctx.RefinementControl.propertyName);


Now you would think that this function would return a boolean type variable, but it doesn’t, it’s a string. 

 

Srch.Refinement.getExpanded = function (f) {

    var e = "refinementExpandCookieName_" + f,

        a = document.cookie;

    if (!Srch.U.e(a)) {

        var b = a.indexOf(e + "=");

        if (b !== -1) {

            b = b + e.length + 1;

            var d = a.indexOf(";", b);

            if (d === -1) d = a.length;

            var c = a.substring(b, d);

            if (!Srch.U.n(c)) c = unescape(c);

            return c

        }

    }

    return"true"

};

 

Now take a look at the bottom of the file where our isExpanded string variable is saved for use in Filter_MultiValue_Body.html, the value of isExpanded is a string value of “false”.

 

ctx.RefinementControl["csr_isExpanded"] = isExpanded;

 

Now let’s take a look at Filter_MultiValue_Body.html, notice the line

 

var isExpanded = Boolean(ctx.RefinementControl["csr_isExpanded"]);

 

The JavaScript “Boolean” function when given a single string as an argument will return false only if the string is blank, this means that a string with a value of “false” will return true.  So, to be clear, any string with 1 or more characters will return true from the “Boolean” function.  So you can see the problem, upon rendering, the isExpanded variable in Filter_MultiValue_Body.html is always true.

 

I ran into another issue that was really just unexpected behavior, when you would select a few items to refine on, then click the "Apply" button, the entire refiner would hide itself again.  Duh, that’s what I told it to do.  I had to add some code to determine if there were some refiners selected and override the collapsed state.

 

Anyway, here’s the code in Filter_MultiValue_Body.html.

 

<!--#_

var propertyName = ctx.RefinementControl["csr_propertyName"];

var displayTitle = ctx.RefinementControl["csr_displayTitle"];

var filters = ctx.RefinementControl["csr_filters"];

var isExpanded = Boolean(ctx.RefinementControl["csr_isExpanded"]);

var renderEmptyContainer = Boolean(ctx.RefinementControl["csr_renderEmptyContainer"]);

var useContains = Boolean(ctx.RefinementControl["csr_useContains"]);

var useKQL = Boolean(ctx.RefinementControl["csr_useKQL"]);

var showCounts = Boolean(ctx.RefinementControl["csr_showCounts"]);

 

if($isEmptyString(propertyName) || (!$isNull(renderEmptyContainer) && renderEmptyContainer))

{

_#-->

        <divid="EmptyContainer"></div>

<!--#_

}

else if(!$isNull(filters) && Srch.U.isArray(filters) && !$isEmptyArray(filters))

{

    var expandedStatus = !$isNull(isExpanded) ? isExpanded : true;

    var iconClass = "ms-core-listMenu-item ";

    iconClass += expandedStatus ? "ms-ref-uparrow" : "ms-ref-downarrow";

_#-->

        <divid="Container">

            _#= Srch.U.collapsibleRefinerTitle(propertyName, ctx.ClientControl.get_id(), displayTitle, iconClass) =#_

            <divclass="ms-ref-unselSec" id="UnselectedSection">

                <divid="unselShortList" class="ms-ref-unsel-shortList">

 

Becomes

 

<!--#_

var propertyName = ctx.RefinementControl["csr_propertyName"];

var displayTitle = ctx.RefinementControl["csr_displayTitle"];

var filters = ctx.RefinementControl["csr_filters"];

var isExpanded = ctx.RefinementControl["csr_isExpanded"];

var renderEmptyContainer = Boolean(ctx.RefinementControl["csr_renderEmptyContainer"]);

var useContains = Boolean(ctx.RefinementControl["csr_useContains"]);

var useKQL = Boolean(ctx.RefinementControl["csr_useKQL"]);

var showCounts = Boolean(ctx.RefinementControl["csr_showCounts"]);

 

if($isEmptyString(propertyName) || (!$isNull(renderEmptyContainer) && renderEmptyContainer))

{

_#-->

        <divid="EmptyContainer"></div>

<!--#_

}

else if(!$isNull(filters) && Srch.U.isArray(filters) && !$isEmptyArray(filters))

{

    var expandedStatus = !$isNull(isExpanded) ? (isExpanded == "true" ? true : false) : true;

   

    if (!expandedStatus) {

        for (var i = 0; i < filters.length; i++) {

            var filter = filters[i];

            if(!$isNull(filter)) {

                if (Boolean(filter.IsSelected) == true)

                {

                    expandedStatus = true;

                    break;

                };

            }

        }

    }

    var iconClass = "ms-core-listMenu-item ";

    iconClass += expandedStatus ? "ms-ref-uparrow" : "ms-ref-downarrow";

    var displayStyle = expandedStatus ? "" : "none";

_#-->

        <divid="Container">

            _#= Srch.U.collapsibleRefinerTitle(propertyName, ctx.ClientControl.get_id(), displayTitle, iconClass) =#_

            <divclass="ms-ref-unselSec" id="UnselectedSection"style='display:_#=$htmlEncode(displayStyle)=#_'>

                <divid="unselShortList" class="ms-ref-unsel-shortList">

AutoCollapsedRefiners.zip

Comments (11)
  1. Deepak Koduri says:

    Thanks Dan Budimir. Saved my day….. 🙂

  2. Marie says:

    I followed the instruction but not getting the refiner to collapse.

    Here's what I did:

    I tried placing a space between "divid" and "divclass" as it is not correct that way in html, but that did not make a difference. I also made a copy of each of the two templates and named them the following:

    Filter_MultiValue_Body_collapse.html and Filter_MultiValue_collapse.html

    In the refiner web part, I selected the "Multi-Value Refinement Item collapse" in the display template portion of the Configuration for the refiner.

    I added [Srch.Refinement.setExpanded(ctx.RefinementControl.propertyName, false);] in the Filter_MultiValue_collapse.html page.

    Any help would be appreciated.

  3. Marie says:

    Hello Deepak,

    Any chance you could take a look as to why my code is not auto collapsing?

    I will wait to hear from you first before posting it.

    Thanks

  4. Marie says:

    Hello Dan,

    Sorry, I addressed the wrong person.

    Any chance you could take a look as to why my code is not auto collapsing?

    Thanks

  5. Dan Budimir says:

    Humblest, humblest apologies Marie.  I did not notice the question until today, over a month later!  If you still have this issue please do reach out, I promise to respond promptly.

  6. Jon Miller says:

    I am having the same issue.  It seems style='display:#=$htmlEncode(displayStyle)=#'> is invalid.

  7. Dan Budimir says:

    Should have done this a long time ago.  I added Filter_Default.html, Filter_MultiValue.html and Filter_MultiValueBody.html as an attachment.  Apologies to all for the delay.

  8. Marie says:

    Are these files to replace the old ones? Somehow I got the old ones to work by making yours overwrite the default ones and not using copies. So I made a copy of the out of the box default instead.

    Anyway, I've come across an issue. The refiners are only loading up to 100 items. Beyond that they are over riding the web part config that increases the # items displayed. So with one of my refiners, there are 250 items, but only 100 are showing up. After going into the web part and changing that refiner's count to 250, it reverts back to 100 items after saving, and selecting that refiner. What do you think is going on?

  9. Marie says:

    (I figured out the last issue with the 250 items.)

    My new question is that I have the auto collapse working for the refiner but after expanding the refiner and making selections, when the user hits the "Apply" button (or "Clear"), the refiner collapses again and the user cannot see what they filtered on. Is there a way of having an exception for those functions to stay open, perhaps with an else statement?

  10. Marie says:

    DUH, you already answered this in your post…sorry. Got the new files and will try them out.

  11. WebWmn says:

    Thank you so much, Dan.

Comments are closed.

Skip to main content