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">
Comments
Anonymous
October 30, 2014
Thanks Dan Budimir. Saved my day..... :)Anonymous
December 04, 2014
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.htmlIn 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.Anonymous
December 07, 2014
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.ThanksAnonymous
December 08, 2014
Hello Dan,Sorry, I addressed the wrong person.Any chance you could take a look as to why my code is not auto collapsing?ThanksAnonymous
January 12, 2015
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.Anonymous
January 20, 2015
The comment has been removedAnonymous
February 11, 2015
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.Anonymous
May 28, 2015
The comment has been removedAnonymous
June 16, 2015
(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?Anonymous
June 16, 2015
DUH, you already answered this in your post...sorry. Got the new files and will try them out.Anonymous
July 21, 2015
Thank you so much, Dan.