I wanted to document an easy way to add auto complete functionality to a search box in ASP.NET MVC using the jQuery UI Autocomplete widget. I've tried to make the code simple while still being left with a workable example. This solution is a simplified version of this functionality I saw while watching the free ASP.NET MVC 3 video series from K. Scott Allen of Pluralsight.
Layout
First, below is the layout file we are using for this example. Nothing special here. Only thing to really note is the two optional sections: styles and scripts. These are used on the View to add specific CSS and JavaScript needed for the example.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>ASP.NET MVC Example</title>
@Styles.Render("~/Content/css")
@RenderSection("styles", required: false)
</head>
<body>
@RenderBody()
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</body>
</html>
View
Now let's talk about the View. The jQuery UI AutoComplete widget is being setup in the scripts @section by calling the jQuery UI autocomplete method and passing the properties I want to use. I am setting the source to the SearchAutoCompleter action method of my SearchExample Controller (see the next section). I am also setting minLength to 2. This means the call to the action method will not happen unless the user enters at least 2 characters.
<h2>Autocomplete Enabled Search</h2>
@using (Html.BeginForm())
{
<input type="text" name="searchQuery" id="autocomplete" />
<input type="submit" value="Search" />
}
@section scripts
{
<script type="text/javascript" src="~/Scripts/jquery-ui-1.8.24.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#autocomplete").autocomplete({
source: "@Url.Action("SearchAutoCompleter","SearchExample")",
minLength: 2
});
});
</script>
}
Controller
Below is an example of what you would have in your controller's action method. I am showing a LINQ query that could be accessing a LINQ to SQL or Entity Framework repository, etc. Here I am just getting 10 distinct items, but you can do whatever logic you need to do. Notice that I am creating an anonymous type with one property named "label". This is what the jQuery UI AutoComplete widget is expecting. Note that label is case sensitive here. Finally, the collection is returned as Json for the AutoComplete widget to process.
public class SearchExampleController : Controller
{
public JsonResult SearchAutoCompleter(string term)
{
var myObjects = (from o in myRepository.MyClass
where o.ColumnToSearchOn.Contains(term)
select new{
label = o.ColumnToSearchOn
}).Distinct().Take(10);
return Json(myObjects, JsonRequestBehavior.AllowGet);
}
}
Resources
The jQuery UI Dialog does not seem to play nicely with the ASP.NET AJAX UpdatePanel. After doing a partial page postback using an UpdatePanel the jQuery UI Dialog div would no longer function. Thanks to Stack Overflow and some blog posts I discovered that you need to add some code to hook into the ASP.NET AJAX JavaScript pageLoaded event and this will reinitialize the jQuery UI Dialog div every time. We also need to append the div to the form element so that any ASP.NET buttons on the div will post back to our page. In the following JavaScript snippet my jQuery modal dialog div has an ID of "myDiv". Also, in this example we are setting up the dialog to be modal and autoOpen equal to false.
<script type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(function (evt, args) {
var myDiv = $("#myDiv").dialog({ autoOpen: false, modal: true, open: function (type, data) {
$(this).parent().appendTo("form");
}
});
});
</script>