Search Navigation Without Creating New Pages (JavaScript) – SharePoint 2013

In the project I’m working on they asked me to create a JS file that would change the Result Sources on the fly as the user clicked on the navigation links. So after googling a bit I’ve stumbled upon Elio Struyf’s post where he changes the Result Sources based on the query, so that pointed me in the right direction… At the beginning my idea was to make it so that it changed the Result Source based on a parameter in the query string, so I thought that Elio’s code would be a great base and that I just needed to make the changes so that it would pull the values from the QueryString instead of the query for the search. Right?

Wrong. That approach turned out to be a bit more difficult than expected. To start with I learned that the SharePoint site navigation didn’t account for query parameters so I decided that I would change the href of the links via the JavaScript file that I was writing, that was easy enough… But still the code was not executing, after a careful look at the situation I realized that the fillKeywordQuery function was not being called. The problem was that in the project we don’t use a default Search Box Web Part, we use a simple web part that fills the results onto a customized Search Results Web Part so the function was never being called. I added a default Search Box Web Part and noted that when I clicked on the search image the code was executing just fine.

In the end I decided to go with a different approach that doesn’t depends on the QueryString, it just changes the behavior of the fillKeywordQuery each time you click on the navigation links.

So the first thing that I had to do was to remove the href and the onclick from all the links so that they wouldn’t redirect me to the page that was assigned on the SharePoint side. To do that I used just some simple jQuery:

//Save the original fillKeywordQuery function
if (typeof Srch.U.fillKeywordQuery !== 'undefined') {
 var originalFillKeywordQuery = Srch.U.fillKeywordQuery;
}

var links = $('li.ms-srchnav-item > h2.ms-displayInline > a');
links.prop('onclick','');
links.prop('href','#'); //I'm leaving the href set so that the default SharePoint styles continue to work

After that I had to go through each link and assign the click function that would do the specific Result Source change:


links.each(function(i) {
   var item = $(this);
   if(item.attr('title').indexOf(' All') > -1){
      item.click(function(){
         Srch.U.fillKeywordQuery = function(query, dp) {
           //Set the Result Source
           dp.set_sourceID("a7b9a73f-c771-4237-a1b5-c8c44beb462a");
           //Continue processing the KeywordQuery with the default function
           originalFillKeywordQuery(query, dp);
           selectedClassLink(links, item);
        };
      });
   }
   else if(item.attr('title').indexOf(' Documents') > -1) {
      item.click(function(){
         Srch.U.fillKeywordQuery = function(query, dp) {
           //Set the Result Source
           dp.set_sourceID("24f2f75a-6c8d-4657-b9b0-181204e8b92e");
           //Continue processing the KeywordQuery with the default function
           originalFillKeywordQuery(query, dp);
           selectedClassLink(links, item);
        };
     });
   }
}

function selectedClassLink (links, sLink) {
   links.attr('class','ms-srchnav-link');
   sLink.removeClass('ms-srchnav-link');
   sLink.addClass('ms-srchnav-link-selected');
}

In my case I also needed to call the fillKeywordQuery myself since the web part that we’re using doesn’t call it. If that is your case you’ll also need to set a KeywordQuery and get the DataProvider and call the function on each of the clicks from the links.

And when you put this in you realize that the Results Web Part is not refreshing… So we need to make it refresh on each of the click functions of the links. And again come Elio Struyf to give the helping hand, he also has a post where he explains how to refresh the Results web part automatically so basing myself on that I was able to change a couple of things to make it work on my solution.

So here’s the final code:

var keywordQuery,datap;//To be used when manually calling the fillKeywordQuery function.
$(document).ready(function(){
	var clientContext = new SP.ClientContext(document.location.href);
	var contextSite = clientContext.get_site();
	datap = $getClientControl($('#DataProvider')[0]);
	EnsureScript("sp.search.js",TypeofFullName("Microsoft.SharePoint.Client.Search.Query.KeywordQuery"),datap.$$d_$54_3)
	keywordQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(clientContext);
	changeNavLinks();
});

//Save the original fillKeywordQuery function
if (typeof Srch.U.fillKeywordQuery !== 'undefined') {
	var originalFillKeywordQuery = Srch.U.fillKeywordQuery;
}

//Change the way the Search Navigation Web Part links function
function changeNavLinks() {
	var links = $('li.ms-srchnav-item > h2.ms-displayInline > a');
	links.prop('onclick','');
        links.prop('href','#');
	links.each(function(i) {
		var item = $(this);
		if(item.attr('title').indexOf(' All') > -1){
			item.click(function(){
				overrideFKQ('6fa34605-8405-43c3-b484-a04508a80ebc');
				Srch.U.fillKeywordQuery(keywordQuery,datap);
				var queryState = new Srch.QueryState();
				var queryStateArgs = new Srch.QueryEventArgs(queryState);
				$getClientControl($('#Result')[0]).raiseQueryReadyEvent(queryStateArgs);
				selectedClassLink(links, item);
			});
		}
		else if(item.attr('title').indexOf(' Documents') > -1) {
			item.click(function(){
				overrideFKQ('a7b9a73f-c771-4237-a1b5-c8c44beb462a');
				Srch.U.fillKeywordQuery(keywordQuery,datap);
				var queryState = new Srch.QueryState();
				var queryStateArgs = new Srch.QueryEventArgs(queryState);
				$getClientControl($('#Result')[0]).raiseQueryReadyEvent(queryStateArgs);
				selectedClassLink(links, item);
			});
		}
	});
}

function overrideFKQ(sourceID) {
	Srch.U.fillKeywordQuery = function(query, dp) {
		//Set the Result Source
		dp.set_sourceID(sourceID);
		//Continue processing
		originalFillKeywordQuery(query, dp);
	};
}

function selectedClassLink (links, sLink) {
	links.attr('class','ms-srchnav-link');
	sLink.removeClass('ms-srchnav-link');
	sLink.addClass('ms-srchnav-link-selected');
}

There you have it. Hope this helps you and thanks again to Elio Struyf for his posts that helped me make this code.

If you have any questions or comments please leave them below and I’ll try to answer them.

Advertisements