The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.
NOTE: The following blog post has been updated for compatibility with the latest Sitefinity versions.
Autocomplete functionality has been one of the most useful things implemented on a search box. Not only the displayed suggestions can speed up your search by simply clicking on one of them instead of typing the full term, but also they can give you a really handy "on the fly search for search terms" while typing, and give you a better search term hint.
There are several factors that need to be taken into account when making your own autocomplete functionality:
Most autocomplete samples that you'll find rely on a predefined array of data to pull suggestions from, which is not the best option for our use case scenario, that's why we've taken a slightly different approach. Since Sitefinity is using the Lucene engine for it search indexing functionality we can take advantage of the generated search index and search for keyword suggestions on the fly making an AJAX call to a WebService that will pull the data for us. The service consists of a single method that does all the work for us:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public
class
SearchAutoComplete : ISearchCompleteService
{
public
string
[] GetKeywords(
string
catalogueName,
string
term)
{
//Adding * allows wildcard search. For more info check http://www.lucenetutorial.com/lucene-query-syntax.html
var searchTerm = term +
'*'
;
//these are the Fields we'll search in
var searchFields =
new
string
[] {
"Title"
};
//get the Sitefinity Search service
var searchService = Telerik.Sitefinity.Services.ServiceBus.ResolveService<ISearchService>();
//Build the query
var compiledQuery = searchService.BuildQuery(searchTerm, searchFields, SystemManager.CurrentContext.AppSettings.Multilingual);
//Get the search results
var result = searchService.Search(catalogueName, compiledQuery,
null
, 0, 10,
null
);
var strResult = result.Select(res => res.GetValue(
"Title"
));
return
strResult.ToArray();
}
We're passing as parameters the user typed string (the text currently being entered in the search box) and the name of the search index specified for this search box.
We then resolve the Sitefinity Search service,and build the search query.
As we're interested in pulling just the Title of the items, the specified search field include only "Title". What's interesting is the way Lucene allows us to do wildcard searches, which is very useful in the current case as we can simply search for "Sitef*" which will return all results in the search index whose title starts with "Sitef".
In the call to searchService.Search the returned results are sorted by default by relevance, and we're taking the top 10 results.
For the frontend representation of the autocomplete suggestions we'll be using jQuery UI autocomplete plugin which offers a convenient solution to several problems you might have to deal with if implementing your own autocomplete suggestions visualization, namely:
If you want to implement this from scratch maybe the easiest approach would be to define a <div> element which you'll populate with the returned keywords and then add them to a list, each item having an onClick implementation that would set its value as a value in the search box.
Here's how you can very easily accomplish this with jQueryUI autocomplete on the default Sitefinity SearchBox template:
<%@ Control Language="C#" %>
<%@ Register TagPrefix="sitefinity" Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" %>
<
sitefinity:ResourceLinks
ID
=
"resourcesLinks"
runat
=
"server"
>
<
sitefinity:ResourceFile
JavaScriptLibrary
=
"JQuery"
/>
<
sitefinity:ResourceFile
JavaScriptLibrary
=
"JQueryUI"
/>
</
sitefinity:ResourceLinks
>
<
link
href
=
"http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/themes/base/jquery-ui.css"
rel
=
"stylesheet"
type
=
"text/css"
/>
<%--remove the below style if you want to have the loading icon in the searchbox--%>
<
style
type
=
"text/css"
>
.ui-autocomplete-loading {
background: white right center no-repeat !important;
}
</
style
>
<
fieldset
id
=
"main"
class
=
"sfsearchBox"
runat
=
"server"
>
<
asp:TextBox
ID
=
"searchTextBox"
runat
=
"server"
CssClass
=
"sfsearchTxt"
/>
<
asp:Button
ID
=
"searchButton"
runat
=
"server"
Text="<%$Resources:SearchResources, Search %>" OnClientClick="return false;" CssClass="sfsearchSubmit" />
<
asp:HiddenField
runat
=
"server"
ID
=
"searchIndexName"
/>
</
fieldset
>
<
script
type
=
"text/javascript"
>
$(document).ready(function () {
var id = "#" + "<%= searchTextBox.ClientID %>";
var indexId = "#" + "<%= searchIndexName.ClientID %>";
var indexName = $(indexId).val();
var url = "/Sitefinity/Public/Services/SearchCompletion/AutoCompleteService.svc/GetKeywords?catalogueName=" + indexName;
$(id).autocomplete({
minLength: 2,
source: url
});
});
</
script
>
If you prefer to implement your own styling for the autocomplete suggestions you don't need to load the default ones, or simply override some of them like shown in the above sample. Please make sure to specify the correct path to where your service is hosted, in our case this is under /Sitefinity/Public/Services/SearchCompletion/
folder. For your convenience I'll be attaching the service hosting to the sample as well.
Since we need to pass the search index name to the service, we have added a HiddenField control above, which we'll be setting in a custom implementation of the SearchBox widget, inheriting from the default one like this:
public
class
SearchBoxCustom:SearchBox
{
public
override
string
LayoutTemplatePath
{
get
{
return
layoutTemplatePath;
}
set
{
base
.LayoutTemplatePath = value;
}
}
protected
virtual
HiddenField SearchIndexName
{
get
{
return
this
.Container.GetControl<HiddenField>(
"searchIndexName"
,
true
);
}
}
protected
override
void
InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
{
base
.InitializeControls(container);
this
.SearchIndexName.Value = IndexCatalogue;
}
public
static
readonly
string
layoutTemplatePath =
"~/Controls/Lucene_AutoComplete/SearchBoxTemplate.ascx"
;
}
The only other thing worth noting is the specified layoutTemplatePath
which you can either change to reflect your folder structure where you've placed the modified template or use Virtual path Provider if you'll be using it as an embedded resource.
Please find attached an archive of the sample folder - you can simply extract it in your SitefinityWebApp solution, add the service hosting under the /Sitefinity/Public/Services folder and adjust any paths wherever necessary (if you'll be placing the template or service in a different folder). Then simply build the project and register the SearchResultsCustom custom control in your PageControls toolbox - you'll be able to use it as any other widget on any Sitefinity page. Here's a short demonstrative video on setting this functionality up, and using the modified SearchBox widget with the autocomplete functionality.
Attachments: SF_Search_Autocomplete
View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites
Progress collects the Personal Information set out in our Privacy Policy and the Supplemental Privacy notice for residents of California and other US States and uses it for the purposes stated in that policy.
You can also ask us not to share your Personal Information to third parties here: Do Not Sell or Share My Info
We see that you have already chosen to receive marketing materials from us. If you wish to change this at any time you may do so by clicking here.
Thank you for your continued interest in Progress. Based on either your previous activity on our websites or our ongoing relationship, we will keep you updated on our products, solutions, services, company news and events. If you decide that you want to be removed from our mailing lists at any time, you can change your contact preferences by clicking here.