Introduction
SearchBoxAutoComplete
is auto-completion jQuery widget that enables you to search the categorized data through the hierarchies, i.e., Brand/Categories/Products or Category/Brands/Products.
Background
Many Virtual Stores are offering Products classified by Categories and Brands. Usually there are a lot of Categories, Sub-Categories and Brands, and a user has difficulties to find the appropriate Category, Brand or Product.
SearchBoxAutoComplete
widget enables a user to quickly find and select the wanted Category or Brand. By entering 2 or more characters, the user can filter down the list to better matches.

After user selects Category, the widget offers a drop-down list with all the Brands that products of the selected Category belong.
If user selected the Brand, widget would offer drop-down list with all the Categories that Brand’s Products belong to.

User can select multiple items from the offered list, or enter new characters to start a new hierarchy. Results from multiple hierarchies are aggregated at the server.
Here is the sample of 2 hierarchies: categ1: brand1: brand2; categ2: brand3:
SearchBoxAutoComplete jQuery Widget
jQuery Widgets resolve the problem that jQuery Plugins have with associating an JavaScript Object with a DOM element, avoiding circular references and memory leaks.
SearchBoxAutoComplete
“jquery.ui.searchboxautocomplete.js” widget uses standard “jquery.ui.autocomplete.js” widget.
Instead of hacking the existing widget, SearchBoxAutoCompelete
modifies the behavior of the existing widget by extending or overriding/sub-classing the widget properties, methods and events.
$.widget("ui.searchboxautocomplete", $.ui.autocomplete, {
_create: function () {
...
},
_init: function () {
$.ui.autocomplete.prototype._init.apply(this, arguments);
this.element.bind("searchboxautocompleteclose", function () {
self.options.offeringSecondLevel = false;
});
…
},
options: {
select: function (event, ui) { … },
cache: {},
autocompleteRows: [],
separator: ": ",
…
}
}
SearchBoxAutoCompleteRows widget uses Ajax JSON call to get the data from the server.
List of: AutocompleteRow { category: 'Brands', label:'Bikes', value:11 }
is serialized at the client by:
JSON.stringify(this.options.autocompleteRows).
At the server, it is deserialized with:
var selectedRows = new JavaScriptSerializer().Deserialize<List<AutocompleteRow>>(acRows);
Form
<form id="searchbox" action="/search/productlist" method="post">
<input type="text" id="search" value=""/>
<input id="searchbutton" type="submit" value="Search"/>
<input type="hidden" id="selectedAutocompleteRows" />
</form>
$("#search")
.setSearchText(autocompleteRows)
.searchboxautocomplete({
autocompleteRows: autocompleteRows,
source: function (request, response) {
var term = $.ui.searchboxautocomplete.extractLast(request.term);
var data = this.options.getCachedData(term);
if (data != null) {
response(data);
return true;
}
var that = this;
this.options.lastXhr =
$.getJSON("/Search/GetBrandsAndCategories",
{term:term, acRows:JSON.stringify(this.options.autocompleteRows)},
function (data, status, xhr) {
that.options.setCachedData(term, data);
if (xhr === that.options.lastXhr) {
response(data);
}
})
},
search: function () {
if (term.length < 2) {
return false;
}
}
})
Data are received from server by Ajax $.getJSON()
call. Arguments sent to the server are:
- Last search term
- Array of already selected rows
This is done by:
{ term: term, acRows: JSON.stringify(this.options.autocompleteRows) }
Data returned from the server are rendered by function response(data)
called upon successful Ajax call.
Default fields are: category, label, value. You can override _renderItem
function and display your fields.
Data returned from the server are in JSON format, something like this:
var data = [
{category:"Categories", label:"Mountain Bikes", value:"1"},
{category:"Categories", label:"Road Bikes", value:"2"},
{category:"Categories", label:"Touring Bikes", value:"3"},
{category:"Brands", label:"Mountain Bikes", value:"12"}
]
Here is the MVC 2.0 server method that returns the data in JSON format:
public JsonResult GetBrandsAndCategories(string acRows, string term)
{
var selectedRows = new JavaScriptSerializer()
.Deserialize<List<AutocompleteRow>>(acRows);
var firstRow = selectedRows[0];
term = term.Trim().ToLower();
if (term == "secondlevel")
{
var list = new List<AutocompleteRow>();
if (firstRow.category == "Brands")
{
var brand = Brand.GetById(int.Parse(firstRow.value));
list = brand.Categories
.Select(c => new AutocompleteRow {
category = "Categories", label = c.Name, value = c.Id.ToString()
})
.ToList<AutocompleteRow>();
}
else
{
}
return Json(list, JsonRequestBehavior.AllowGet);
}
}
Demo Data Repository
The structure of data is usually like this:
<categories>
<category id="3" name="Clothing">
<sub-categories>
<sub-category id="22" name="Shorts">
<products>
<product id="841" name = "Men's Sports Shorts, S">
<brands>
<brand id="29" name="Integrated Sport" price="20.00">
<brand id="102" name="Fitness Association" price="19.80">
</brands>
</product>
</products>
</sub-category>
</sub-categories>
</category>
</categories>
History
- 28th June, 2011: Initial post
June 2011. – Present, Freelancer
• Took part in development of Web Platform for automated trading.
Thanks to Lightstreamer.com as the real-time bi-directional data delivery we realized Long Polling Push pattern. Also, thanks to ASP.NET MVC 4 mobile features, application renders different HTML markups for different display devices, mobile specific or agent specific (i.e. iPhone).
As the Data Access Layer, we used SQL Server and Entity Framework Repository Pattern.
At client side intensive usage of jQuery, Bootstrap, Knockout.js and Widgets developed by custom bindings of Knockout.js.
September 2010. – May 2011. TekNuvo
• Developed application for coupon and promotional data for advertisers. Technologies: ASP.NET MVC 3, C#, LINQ, Entity Framework 4.0, Code-First, Scaffolding …
• Extracted and integrated Lucene Search Modules from Orchard CMS Project Source.
• Using Unity as Dependency Injection Container, and Interfaces instead of specific classes, i.e. accessing data through an abstract repository interface, we enabled easy way of unit testing. Used TDD as the method of a design, specifying desired behaviors in the form of unit tests, and then provided implementations to fit.
• Developed several jQuery plugins.
• Developed Shopping Cart application using “ASP.NET MVC 2”, “LINQ to SQL” and NUnit.
March 2008. – August 2010. Mogul Balkan
• Developed Windows Service for integration of Active Directory Groups and Users with SharePoint Groups and Users.
• Integration of InfoPath Forms services with SharePoint.
Developed PowerShell script for automatic unpacking, modifying and packaging of the InfoPath Forms.
• Created custom Moss 2007 Publishing Portal Site Definition with automatic creation of sites structure for extranet project.
• Developed Publishing Feature for WSS 3.0 only.
• Customization and extension of Content Query Web Part.
• Customization of CQWP XSLT files.
• Deployment of SharePoint packages using VSeWSS 1.3 and WSPBuilder
• Deploymen