{"id":1581,"date":"2015-09-21T21:55:06","date_gmt":"2015-09-21T20:55:06","guid":{"rendered":"http:\/\/blog.repsaj.nl\/?p=1581"},"modified":"2016-02-09T17:28:14","modified_gmt":"2016-02-09T16:28:14","slug":"o365-sharepoint-search-dropdown-refiner-template","status":"publish","type":"post","link":"http:\/\/blog.repsaj.nl\/index.php\/2015\/09\/o365-sharepoint-search-dropdown-refiner-template\/","title":{"rendered":"[O365] SharePoint Search dropdown refiner template"},"content":{"rendered":"<p>In my <a href=\"http:\/\/blog.repsaj.nl\/index.php\/2015\/09\/o365-autocomplete-on-taxonomy-refiners\/\" target=\"_blank\">previous O365 post<\/a>, I showed how you can make use of jQuery and jQuery UI to make a search refiner filter template that supports autocomplete on the &#8220;other&#8221; textbox shown in a multivalued dropdown. With that idea in mind, I imagined it would be pretty easy to use the same concept to create a filter template that shows a dropdown list with possible filter values. And it turns out it is pretty simple, so here are the steps.<!--more--><\/p>\n<p>As with my previous post, I&#8217;m not going to outline all of the steps to create a filter display template, instead I&#8217;d like to refer to <a href=\"https:\/\/twitter.com\/eliostruyf\" target=\"_blank\">@eliostruyf<\/a>&#8216;s blog for that (see <a href=\"http:\/\/www.eliostruyf.com\/part-1-create-first-search-refiner-control-template\/\" target=\"_blank\">here<\/a>). As you&#8217;ll find, the default multivalued dropdown template uses two files;\u00a0<strong>Filter_MultiValue\u00a0<\/strong>and\u00a0<strong><strong>Filter_MultiValue_Body<\/strong><\/strong>. So as with the autocomplete example, we&#8217;ll make copies of these.<\/p>\n<p>In this case, there is no real need to change the Filter_Multivalue file, except for loading a\u00a0custom javascript file like this:<\/p>\n<pre class=\"prettyprint\">&lt;script&gt;\r\n  $includeScript(\"\",\"~sitecollection\/Scripts\/yourscriptfile.js\");\r\n&lt;\/script&gt;\r\n<\/pre>\n<p>The rendering of the body of the filter is done in the Filter_Multivalue_Body file. Normally you&#8217;ll see the values rendered like this:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-1551\" src=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/taxonomyrefiner.png\" alt=\"taxonomyrefiner\" width=\"166\" height=\"513\" srcset=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/taxonomyrefiner.png 166w, http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/taxonomyrefiner-97x300.png 97w\" sizes=\"(max-width: 166px) 100vw, 166px\" \/><\/p>\n<p>What we&#8217;d like to do is change this list for a dropdown which is way more convenient for use with a larger number of choices. Remember though, you might want to consider the autocomplete one whenever your list is becoming too large.<\/p>\n<p>To do so, we disable the rendering of unselected items. Leave the selected ones rendered so the user can see what selection he or she made. To do so, change the following\u00a0lines (50- 86):<\/p>\n<pre class=\"prettyprint\">&lt;!--#_ \r\nfor (var i = 0; i &lt; filters.length; i++){\r\n    var filter = filters[i];\r\n    if(!$isNull(filter)){\r\n        var isSelected = Boolean(filter.IsSelected);\r\n        var inputName = propertyName + '_ChkGroup';\r\n        var inputId = inputName + \"_\" + filter.RefinementName;\r\n        var nameClass = \"ms-ref-name \" + (showCounts ? \"ms-displayInline\" : \"ms-displayInlineBlock ms-ref-ellipsis\");\r\n_#--&gt;\r\n        &lt;div id=\"Value\"&gt;\r\n&lt;!--#_\r\n        if(isSelected) {\r\n_#--&gt;\r\n            &lt;input type=\"checkbox\" class=\"ms-padding0 ms-margin0 ms-verticalAlignMiddle\" id=\"_#= $htmlEncode(inputId) =#_\" name=\"_#= $htmlEncode(inputName) =#_\" data-displayValue=\"_#= $htmlEncode(filter.RefinementName) =#_\" value=\"_#= $htmlEncode(filter.RefinementToken) =#_\" checked=\"\" \/&gt;\r\n&lt;!--#_\r\n        } else {\r\n_#--&gt;\r\n            &lt;input type=\"checkbox\" class=\"ms-padding0 ms-margin0 ms-verticalAlignMiddle\" id=\"_#= $htmlEncode(inputId) =#_\" name=\"_#= $htmlEncode(inputName) =#_\" data-displayValue=\"_#= $htmlEncode(filter.RefinementName) =#_\" value=\"_#= $htmlEncode(filter.RefinementToken) =#_\" \/&gt;\r\n&lt;!--#_\r\n        }\r\n_#--&gt;\r\n            &lt;label for=\"_#= $htmlEncode(inputId) =#_\" class='_#= nameClass =#_'&gt;\r\n            _#= $htmlEncode(filter.RefinementName) =#_\r\n&lt;!--#_\r\n          if (showCounts) {\r\n_#--&gt;\r\n            &lt;span id='RefinementCount' class='ms-ref-count ms-textSmall'&gt; (_#= $htmlEncode(Srch.U.toFormattedNumber(filter.RefinementCount)) =#_) &lt;\/span&gt;\r\n&lt;!--#_\r\n          }\r\n_#--&gt;\r\n            &lt;\/label&gt;\r\n        &lt;\/div&gt;\r\n&lt;!--#_\r\n    }\r\n}\r\n_#--&gt;\r\n<\/pre>\n<p>To:<\/p>\n<pre class=\"prettyprint\">&lt;!--#_\r\n    var allSelected = true;\r\n\r\n    for (var i = 0; i &lt; filters.length; i++){\r\n        var filter = filters[i];\r\n        if(!$isNull(filter)){\r\n            var isSelected = Boolean(filter.IsSelected);\r\n            allSelected = allSelected &amp;&amp; isSelected;\r\n            var inputName = propertyName + '_ChkGroup';\r\n            var inputId = inputName + \"_\" + filter.RefinementName;\r\n            var nameClass = \"ms-ref-name \" + (showCounts ? \"ms-displayInline\" : \"ms-displayInlineBlock ms-ref-ellipsis\");\r\n_#--&gt;\r\n&lt;!--#_\r\n            if(isSelected) {\r\n_#--&gt;\r\n&lt;div id=\"Value\"&gt;\r\n    &lt;input type=\"checkbox\" class=\"ms-padding0 ms-margin0 ms-verticalAlignMiddle\" id=\"_#= $htmlEncode(inputId) =#_\" name=\"_#= $htmlEncode(inputName) =#_\" data-displayValue=\"_#= $htmlEncode(filter.RefinementName) =#_\" value=\"_#= $htmlEncode(filter.RefinementToken) =#_\" checked=\"\" \/&gt;\r\n    &lt;label for=\"_#= $htmlEncode(inputId) =#_\" class='_#= nameClass =#_'&gt;\r\n        _#= $htmlEncode(filter.RefinementName) =#_\r\n    &lt;\/label&gt;\r\n&lt;\/div&gt;\r\n\r\n&lt;!--#_      } _#--&gt;\r\n&lt;!--#_\r\n        }\r\n    }\r\n_#--&gt;\r\n<\/pre>\n<p>Without any values selected (default) the template won&#8217;t render a thing any more. Note that I added a variable &#8220;allSelected&#8221; which tracks whether all the items rendered are selected items. If this is the case, the user already selected some items and I do not want the dropdown to render any more. Whether you also want to do this is totally up to you.<\/p>\n<p>Next,\u00a0we&#8217;ll add some code to render a pretty straightforwarde HTML &lt;select&gt; control with &lt;option&gt; items for each refiner value:<\/p>\n<pre class=\"prettyprint\">&lt;!--#_ if(!allSelected) { _#--&gt;\r\n\r\n&lt;div id=\"OtherValue\" style=\"width: 260px;\"&gt;\r\n    Select the items you want to filter on and then click 'apply' to filter the results. Select 'clear' to clear the filters to reselect different values.\r\n&lt;\/div&gt;\r\n&lt;select onchange=\"Custom.Jsom.Refiners.addDropdownInput($(this), this.value);\" id=\"_#= $htmlEncode(propertyName) =#__select\"&gt;\r\n    &lt;option value=\"\"&gt;Select a value&lt;\/option&gt;\r\n\r\n    &lt;!--#_\r\n        for (var i = 0; i &lt; filters.length; i++){\r\n            var filter = filters[i];\r\n            if(!$isNull(filter)){\r\n                var inputName = propertyName + '_ChkGroup';\r\n                var inputId = inputName + \"_\" + filter.RefinementName;\r\n                var nameClass = \"ms-ref-name \" + (showCounts ? \"ms-displayInline\" : \"ms-displayInlineBlock ms-ref-ellipsis\");\r\n    _#--&gt;\r\n    &lt;option value=\"_#= $htmlEncode(filter.RefinementName) =#_\"&gt;_#= $htmlEncode(filter.RefinementName) =#_&lt;\/option&gt;\r\n    &lt;!--#_\r\n            }\r\n        }\r\n    _#--&gt;\r\n\r\n&lt;\/select&gt;\r\n\r\n&lt;!--#_ } _#--&gt;\r\n<\/pre>\n<p>And there you are, the refiner values are now rendered as a dropdown in SharePoint:<\/p>\n<p><a href=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownclosed.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-1583\" src=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownclosed.png\" alt=\"refiner_dropdownclosed\" width=\"271\" height=\"158\" \/><\/a><\/p>\n<p>And with values:<\/p>\n<p><a href=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownopened.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-1584\" src=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownopened.png\" alt=\"refiner_dropdownopened\" width=\"274\" height=\"449\" srcset=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownopened.png 274w, http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownopened-183x300.png 183w\" sizes=\"(max-width: 274px) 100vw, 274px\" \/><\/a><\/p>\n<p>Ok, now obviously we&#8217;re not done yet as this is a\u00a0<strong>multivalued\u00a0<\/strong>refiner and by default a dropdown only allows you to select a single value. So I added a method which is called on the dropdowns &#8220;onchange&#8221; event. This method looks like this:<\/p>\n<pre class=\"prettyprint\">function addAutocompleteInput(input, item) {\r\n    var container = input.parent().parent().parent();\r\n    var name = item.label;\r\n\r\n\r\n    var txtInputName = input.attr('name');\r\n    var inputName = txtInputName.substring(0, txtInputName.indexOf('_')) + '_ChkGroup';\r\n    var inputId = inputName + '_' + name;\r\n    var inputValue = 'equals(\"' + name + '\")';\r\n\r\n    addInput(inputId, inputName, inputValue, name, container);\r\n}\r\n\r\nfunction addInput(inputId, inputName, inputValue, value, container) {\r\n    var inputClass = \"ms-padding0 ms-margin0 ms-verticalAlignMiddle\";\r\n    var nameClass = \"ms-ref-name ms-displayInlineBlock ms-ref-ellipsis\";\r\n\r\n    var div = $('&lt;div \/&gt;', { id: 'Value' }).prependTo(container);\r\n    $('&lt;input \/&gt;', { type: 'checkbox', id: inputId, name: inputName, 'data-displayValue': value, value: inputValue, checked: '', class: inputClass }).appendTo(div);\r\n    $('&lt;span&gt;&amp;#160;&lt;\/span&gt;').appendTo(div);\r\n    $('&lt;label \/&gt;', { 'for': inputId, text: value, class: nameClass }).appendTo(div);\r\n}\r\n<\/pre>\n<p>I split this into two methods because I re-used the addInput method for the autocomplete box, you don&#8217;t need to if you don&#8217;t want to. The code is pretty self-explanatory I think, basically it renders a &lt;div id=&#8221;Value&#8221;&gt; container, holding a &lt;input&gt; checkbox with a &lt;label&gt; for the text value. This is exactly how SharePoint would render it too, which you can see in the original filter template code. The name of the &lt;select&gt; is used to construct a name for the checkbox controls and the selected value and label of the refiner are used to put into the select box.<\/p>\n<p>When the user now selects a value from the dropdown, it&#8217;s rendered just like a regular refiner value:<\/p>\n<p><a href=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownselected.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-1586\" src=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdownselected.png\" alt=\"refiner_dropdownselected\" width=\"284\" height=\"219\" \/><\/a><\/p>\n<p>As you can see, you can select multiple values now and hitting &#8220;Apply&#8221; will refine your search based on all selected values.<\/p>\n<p>One last thing you will probably need to to is increase the number of refiner values SharePoint will return. By default this number is set to 10, which will limit the amount of refiner options (thus dropdown options) to just 10, in which case a dropdown isn&#8217;t really required. I haven&#8217;t found a limit for this number just yet, but with larger numbers a dropdown isn&#8217;t really the best control any more in my opinion. I would probably try to limit it to about 100 items. You can find this setting in the refiner settings of the refiner web part:<\/p>\n<p><a href=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdown_number.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-1591\" src=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdown_number.png\" alt=\"refiner_dropdown_number\" width=\"469\" height=\"223\" srcset=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdown_number.png 469w, http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2015\/09\/refiner_dropdown_number-300x143.png 300w\" sizes=\"(max-width: 469px) 100vw, 469px\" \/><\/a><\/p>\n<p>And that&#8217;s it, next to our already awesome <a href=\"http:\/\/blog.repsaj.nl\/index.php\/2015\/09\/o365-autocomplete-on-taxonomy-refiners\/\" target=\"_blank\">autocomplete refiner<\/a> we now have a dropdown refiner as well. Enjoy!<\/p>\n<p><strong>Update:\u00a0<\/strong>the above mentioned Elio Struyf also has a solution for building a dropdown refiner template. I did this one just for practice and didn&#8217;t search for existing solutions, but I definitely recommend you check it out and choose the one you think is best!\u00a0http:\/\/www.eliostruyf.com\/part-4-create-dropdown-search-refiner-control\/<\/p>\n<p><strong>Update:<\/strong> I&#8217;ve uploaded the two HTML files as example how you can implement this.\u00a0Download here:<\/p>\n<p><iframe loading=\"lazy\" width=\"98\" height=\"120\" src=\"https:\/\/onedrive.live.com\/embed?cid=26C400A05A6FFC73&amp;resid=26C400A05A6FFC73%21396864&amp;authkey=AG0bYnXz4DBTJ24\" frameborder=\"0\" scrolling=\"no\"><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my previous O365 post, I showed how you can make use of jQuery and jQuery UI to make a search refiner filter template that supports autocomplete on the &#8220;other&#8221; textbox shown in a multivalued dropdown. With that idea in mind, I imagined it would be pretty easy to use the same concept to create<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[34],"tags":[129,48,39,139],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3KFR1-pv","_links":{"self":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/posts\/1581"}],"collection":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/comments?post=1581"}],"version-history":[{"count":0,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/posts\/1581\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/media?parent=1581"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/categories?post=1581"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/tags?post=1581"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}