Thursday, June 20, 2013

Extending the existing search box in SharePoint 2013 with search as you type functionality

Back in February Murad Sæter blogged about using jQuery autocomplete to get real search results from SharePoint 2013 while you are entering the query.

image

Note   Executing live searches like this may cause load on your search server. You should monitor the load or restrict your queries if you see a load issue. You can also increase the delay time from the default 100ms to reduce the load.

imageInspired by this on a recent project I wanted to see if I could add this functionality to the existing search box on the search center.

The search box has three settings for search as you type suggestions. Suggestions based on what everyone searches which is recorded over time (or you can manually add suggestions), suggestions matching people names, and personal favorites – which are searches you perform often.

For my search scenario I was creating a page to find collaboration and project sites. Sort of a search based navigation to locate sites on the intranet. In my particular case I did not have any needs for person name results, and decided to re-use the person name container for real searches instead.

The effect is that while you are entering your query, real searches are executed against the Title field and limiting to sites only (contentclass:STS_Web).

The search suggestions functionality in SharePoint 2013 is provided by ajaxtoolkit.js. In order to extend the existing functionality  I had to override the _update function of the AjaxControlToolkit.AutoCompleteBehavior.prototype which is responsible for the search as you type functionality of the search box.

I also chose to use jQuery ajax and the search REST api in order to get my search results.

A simple way of adding the functionality is to drop a script editor web part on the page and simply paste in the code in this post. The code has some inline comments to describe what is going on.

image

<script type="text/javascript">
function Override() {
// Keep a copy of the original function
AjaxControlToolkit.AutoCompleteBehavior.prototype._update2 = AjaxControlToolkit.AutoCompleteBehavior.prototype._update;

// register the searchOnSuccess on the same prototype object in order for the update2 function to keep the
// context with all variables
AjaxControlToolkit.AutoCompleteBehavior.prototype.searchOnSuccess = function(data,prefixText,completionItems,cacheResults) {
var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;

var names = [];
for (var i = 0; i < results.length; i++) {
var title = results[i].Cells.results[3].Value;
// Add highlighting of the search term
var idx = title.toLowerCase().indexOf(prefixText.toLowerCase());
if( idx >= 0) {
var hhtitle = title.substr(0,idx) + "" + title.substr(idx,prefixText.length) + "" + title.substr(idx+prefixText.length);
names.push(hhtitle);
} else {
names.push(title); // fallback if indexof fails
}
/* href = results[i].Cells.results[6].Value; */
}
// put our results in the people name container as we're not using it on our page
completionItems.set_peopleNames(names);
// call the original update function which renders out the results
this._update2(prefixText, completionItems, cacheResults);
};

// Register an overload update function which executes a real search
AjaxControlToolkit.AutoCompleteBehavior.prototype._update = function(prefixText, completionItems, cacheResults) {
var context = this;
$.ajax(
{
// Get top 5 results searching only on title field. Other paramaters can be added as well
// Query term is what the user has entered with a wildcard appended
url: _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?rowlimit=5&querytext='title:\"" + prefixText + "*\"'",
method: "GET",
headers: {
"accept": "application/json;odata=verbose;charset=utf-8",
},
success: function(data){ context.searchOnSuccess(data,prefixText,completionItems,cacheResults);},
error: onError
}
);

function onError (err) {
alert(JSON.stringify(err));
}
}

}

// Replace url to your own jquery path
RegisterSod("jquery.min.js", "/_layouts/15/mAdcOW.SearchSuggestions/js/jquery-1.9.0.min.js");
LoadSodByKey("jquery.min.js", function () {
$(function () {
// Make sure ajaxtoolkit is loaded before registering the functions
ExecuteOrDelayUntilScriptLoaded(Override, 'ajaxtoolkit.js');
});
});
</script>