Creating a Suggestion Dropdown
As usual, the rest of the world is playing catchup to GooglDropdowns in WebGridse. Learn how to create a dropdown that gives autocompleted suggestions, like in Google's search bar.
Join the DZone community and get the full member experience.
Join For FreeThe Ultimate Guide to Dropdowns in ASP.NET MVC Series
- Basics of ASP.NET MVC DropdownLists
- Dropdowns in WebGrids
- Cascading Dropdowns
- Creating a Suggestion Dropdown
As far as dropdowns go, the most popular one on the Internet is Google's AutoSuggest.
As you start to type, Google tries to guess what the user is looking for and provides a dropdown with suggestions so the user doesn't have to type everything.
In the last post of this series, we'll discuss how to create an autosuggest dropdown control for your own UI.
Overview
If you've been following this series, you already know by now that we need to write JavaScript for our control.
For our autosuggest dropdown, we'll use a standard TextBox along with a custom <div> that displays below it.
As the user types in the text box, we'll take their input and send it back to the server using a Web API.
This is probably the only post in the series without a ViewModel since everything is done through JavaScript.
Our WebAPI
For our autosuggest to work, we need a Web API similar to our Cascading Dropdown WebAPI.
It's similar, but instead, we want distinct make and models of cars and we only want 10 of them displayed in the dropdown.
/SearchController.cs
public class SearchController : ApiController
{
[HttpGet]
public Vehicle[] For(string id)
{
var connection = ConfigurationManager.ConnectionStrings["DropdownDatabase"].ToString();
var repository = new VehicleRepository(connection);
var records = repository.Search(id);
return records
.Distinct(new VehicleMakeModelComparer())
.Select(e => new Vehicle { Make = e.Make, Model = e.Model })
.OrderBy(e=> e.Make)
.ThenBy(e=> e.Model)
.Take(10)
.ToArray();
}
}
ViewModels/VehicleMakeModelComparer.cs
public class VehicleMakeModelComparer : IEqualityComparer<Vehicle>
{
public bool Equals(Vehicle x, Vehicle y)
{
var xKey = x.Make + " " + x.Model;
var yKey = y.Make + " " + y.Model;
return xKey.Equals(yKey);
}
public int GetHashCode(Vehicle obj)
{
var key = obj.Make + " " + obj.Model;
return key.GetHashCode();
}
}
Now, when we call our API, it looks like this, /api/search/for/<query>
, and it will return specific JSON to the UI.
Setting Up the UI
As mentioned, our UI only has one TextBox and a <div>.
<div class="form-group">
@Html.Label("SearchLabel", "Search", new { @class = "col-sm-1 control-label" })
<div class="col-sm-2">
@Html.TextBox("SearchTerm", string.Empty, new { @class = "search-term form-control" })
<div class="suggestions hidden">
<ul class="suggest-list list-unstyled" />
</div>
</div>
</div>
We don't have anything in our ".suggestions" until we make our call to our Web API.
Time For Scripting
JavaScript is what powers the autosuggest. It's simple to understand and easy enough to enhance.
Our list is contained in a unordered list named ".suggest-list".
Our script requires the SearchTerm text box to have an onKeyUp event attached to it. Once they press the key, we call the API.
Views/Home/SuggestionDropdown.cshtml (<script> section)
$(function() {
$("#SearchTerm").on("keyup keypress",
function(e) {
var active = $("li.active", ".suggest-list");
if (e.which === 27) {
$(".suggestions").addClass("hidden");
} else if (e.which === 40) {
if (active.length > 0) {
var next = $(active).next();
$(active).removeClass("active");
$(next).addClass("active");
} else {
$("li:first", ".suggest-list").addClass("active");
}
} else if (e.which === 38) {
if (active.length > 0) {
var previous = $(active).prev();
$(active).removeClass("active");
$(previous).addClass("active");
} else {
$("li:last", ".suggest-list").addClass("active");
}
} else if (e.which === 13) {
e.preventDefault();
$(this).val($(active).text());
$(".suggestions").addClass("hidden");
return false;
} else {
// We have a good value w/ no special keys.
var value = $("#SearchTerm").val();
if (value === "") {
$(".suggestions").addClass("hidden");
} else {
var uri = "/api/search/for/" + value;
$(".suggestions").removeClass("hidden");
$.getJSON(uri)
.done(function (data) {
var list = $(".suggest-list");
$(list).empty();
$.each(data,
function (key, value) {
var anchor = "<a href='#'>" +
value.Make +
" " +
value.Model +
"</a>";
$(list).append($("<li></li>")
.html(anchor));
// On mouse click, set the value.
$("a", list).on("click",
function (e) {
e.preventDefault();
var selected = $(this).text();
$(".search-term").val(selected);
$(".suggestions").addClass("hidden");
});
});
});
}
}
});
});
When the user presses a key, we check to see the following codes:
- ESC (27) - Close the dropdown when it's visible.
- Down Arrow (40) - Move to the next option in the dropdown.
- Up Arrow (38) - Move to the previous option in the dropdown.
- Enter (13) - Select the highlighted item in the dropdown.
In the end, when none of our keys are caught, we assume the user is entering their search criteria.
We show the "dropdown" by removing the hidden CSS class and make our call to the Web API.
Once retrieved, we add the items to our list and attach click events to our anchors in the list.
Conclusion
In this final post to our dropdown series, I wanted to show how easy it is to create an autosuggest dropdown. Not only did we make our dropdown list clickable, we also added keyboard events for those keyboard-jockeys who avoid the mouse.
This dropdown series explained the basics of dropdowns, how to use dropdowns inside and outside of webgrids, the multiple ways to implement cascading dropdowns, and, of course, how to create an autosuggest dropdown.
I hope this series has shown a detailed and easy way to implement dropdowns in ASP.NET MVC.
Published at DZone with permission of Jonathan Danylko, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments