Thursday, June 6, 2013

Add a “Clear Filters” link to your search page in SharePoint 2013

Using refiners or filters on a search page is an easy way to narrow down on the content you are looking for. If you need to start from scratch you can just click the search button again, but this may not be the best UI.

I’ve worked on many projects where they also want a “Clear filters” link.

As all calls on the 2013 search page is done using AJAX, the real query is added to the hash part of the url, the part coming after the # character. If you want to clear all filters and the search terms, then you can add what designers call a dummy link with a # to the page, and that will reset your query.

<a href=”#”>Clear filters</a>

A simple solution it so add a Content Editor Web Part above the refiner panel with the above markup.
image

As long as the query originated from the search start page, and you have not changed it, then this will work as your query will be part of the url with ?k=query.

However, if you change your query, the url changes. If your original query was test and the new one was sharepoint your url would look like this:

https://intranet.contoso.com/search/Pages/results.aspx?k=test#k=sharepoint

where the value after the hash is what is actually executed. Clearing the filters with the above link would bring you back to the original search term of test. And when you click a refiner, the query changes completely. Url decoded it looks something like this

https://intranet.contoso.com/search/Pages/results.aspx?k=test#Default={"k":"sharepoint","r":[{"n":"WebTemplate","t":["equals(\"STS\")"],"o":"or","k":false,"m":null}]}

where the search term and refiner has been added into a JSON array assigned to the Default hash part. If you want to reset all filters, we now have to do some javascript manipulation.

var hash = window.location.hash;
if( hash.indexOf('Default') == 1 ) {
    hash = unescape(hash)
    var kIdx = hash.indexOf('"k":'); 
    var rIdx = hash.indexOf('","'); 
    var query = hash.substring(kIdx+5,rIdx);
    query = query.replace(/\\/g, '');
    window.location.href = window.location.pathname + window.location.search + '#k=' + escape(query);
} else {
    window.location.href = window.location.pathname + window.location.search + "#";
}

What the above script does is grab the k part from the JSON array, and remove everything else.

A possibly simpler solution is to use the fact that the search query is part of the document title. This we can do as a one liner, and use following markup instead of the one at the top of the post in the Content Editor Web Part.

<a onclick="window.location.href = window.location.pathname + window.location.search + '#k=' + escape(document.title.substr(document.title.indexOf(':')+2))" style="cursor:pointer">Clear filters</a>

--Update 2016-06-01--

Here's a better piece of code which does it correct. It uses the query group "Default" which works on a search page when you have one result web part. If you have multiple you need to make sure you clear the filters on all or the correct web part.

var scriptManager = Srch.ScriptApplicationManager.get_current()
var queryGroup = scriptManager.queryGroups["Default"];
var searchControls = queryGroup.displays;
for (var i = 0; i < searchControls.length; i++) {
 if (searchControls[i] instanceof Srch.Refinement) {
  searchControls[i].clearAllRefiners();
  break;
 }
}

22 comments:

  1. Thanks a lot.. This was really helpful.. Cheers..

    ReplyDelete
    Replies
    1. Did not clear the results for me .....although it did clear the url parameter ...dont know what am I doing it wrong.....changed the site master page to oslo....and it worked.....wonder what that master page change did....

      Delete
  2. This cleared my "k" parameter from the url ...but did not reset the data in the content search web part.....by reset I mean the default results without filtering....any help would be highly appreciated.....

    ReplyDelete
    Replies
    1. You can also use a custom display template and do it via javascript...might be a better approach.

      Delete
    2. You are right Mikael. Adding the following code to Control Template worked for me:


      jQuery('.ms-srch-sb-searchLink').each(function(){
      var existingFunction = $getClientControl(this).search;
      var inputElement = jQuery('#' + this.id).prev();
      if(!inputElement || inputElement.length < 1) return existingFunction.apply(this, arguments);
      var serachboxId = inputElement[0].id;
      var searchboxEmptyText = jQuery('#' + serachboxId).attr('title');
      if(!searchboxEmptyText) searchboxEmptyText = 'Search...';
      var wrappingFunction = function(a){
      if(a == '' || a == searchboxEmptyText){
      window.location.href = window.location.pathname + window.location.search + '#';
      }
      else{
      return existingFunction.apply(this, arguments);
      }
      };
      $getClientControl(this).search = wrappingFunction;
      });

      Delete
    3. Well... this is good, since you wrote this I had to update my post with the proper code to clear all refinement filters :) Post is updated but here goes as well:

      var scriptManager = Srch.ScriptApplicationManager.get_current();
      var queryGroup = scriptManager.queryGroups["Default"];
      var searchControls = queryGroup.displays;
      for (var i = 0; i < searchControls.length; i++) {
      if (searchControls[i] instanceof Srch.Refinement) {
      searchControls[i].clearAllRefiners();
      break;
      }
      }

      Delete
  3. Thanks a lot the code works fine. Only issue I have noticed is that it only works for authenticated users. When I sign out and do search the search results is not refreshing.
    Any help?

    ReplyDelete
    Replies
    1. But if you select and deselect refiners it works?

      Delete
    2. PLease explain what you mean by select and deselect refiners

      Delete
    3. Click a refiner value, on the regined result, click it again to deselect it.

      Delete
    4. I am not sure if Im doing something wrong. The search results page stil does cache the results of the previous keyword even after I clear the filters manually, this is only happening when I use the search as an anonymous user, the search results from the previous keyword are being cleared when I search as an admin. There is something wrong somewhere I guess.

      Delete
    5. Weird indeed...I think I've read about others having issues with refiners and anonynous users as well in the past. I suggest logging a support ticket.

      Delete
  4. Thanks, This was very helpful!

    ReplyDelete
    Replies
    1. I might have done it different today - and will see if I have time to update this post.

      Delete
  5. Does not work for me - get an error
    Uncaught TypeError: searchControls[i].clearAllRefiners is not a function(…)

    Checked the function api as well, could not find the function clearAllRefiners there. Anything that I'm doing wrong here?

    ReplyDelete
    Replies
    1. I haven't tested the updated code on-prem, but for SPO it works just fine. If you paste it in a browser console window and run it it clears the filters you have set. Are you on-prem, and what patch level?

      Delete
    2. Yes I am trying this on SP2013 patch level for which is 15.0.4753.1000.

      Also, can we do something similar to apply all the filters at one go?

      Delete
  6. Yes! I am also having the same error SP 2013 on-prem Uncaught TypeError: searchControls[i].clearAllRefiners is not a function(…). Any success ?

    ReplyDelete
    Replies
    1. Check if the function is there before calling it...or check if there are new methods on the object which arrived after I wrote this.

      Delete
    2. I had the same problem with on-premise, so instead, it's kind of a hack, but I updated each of them :

      var scriptManager = Srch.ScriptApplicationManager.get_current()
      var queryGroup = scriptManager.queryGroups["Default"];
      var searchControls = queryGroup.displays;
      for (var i = 0; i < searchControls.length; i++) {
      if (searchControls[i] instanceof Srch.Refinement) {
      searchControls[i].get_selectedRefinementControls().forEach(function(item,index){
      searchControls[i].updateRefinersJSON('{\u0022'+item.propertyName+'\u0022:null}');
      })
      break;
      }
      }

      Delete
  7. Hi Mikael! Thank you for the code. one more question: how I have a page with 3 differnt search boxes and 3 different search result webparts. The script always clears all the search boxes. How to to it only for the one?

    ReplyDelete
    Replies
    1. Search in all, and check your URL. Then you need to figure out how to manipulate the URL to remove the parts for the searchbox you want to clear.

      If you use the updated code with JavaScript, then check the line:

      var queryGroup = scriptManager.queryGroups["Default"]

      Default is the first search box on the page, the others will have different names (which you can configure in your .webpart definitions)

      Delete