These days it is not uncommon to have text boxes automatically suggest items based on what we type. The results are further filtered as we type to give us the option to simply select an available item with the mouse or keyboard. One of the first examples of this in the wild was Google Suggest.
Figure 13.1 Google Suggest filters options as you type
A rudimentary implementation of this would simply monitor key-presses and fire off ajax requests for each one. Of course this means that fast typist would trigger many requests, most of which would be immediately discarded for the next request coming in 5 milliseconds. A good implementation will take into account a typing delay and also provide keyboard/mouse support for selecting the items.
Luckily jQuery has an extensive list of plugins available.
The basic idea is you have a simple text box on your page. The jQuery plugin adds the necessary behavior to handle key press events and fire the appropriate Ajax requests off to a URL that will handle the request. The URL needs point to a controller action, and by convention the response is formatted in a special way so the plugin could handle the response.
Assume for our purposes that we wanted to filter US Cities in the text box. The first step is to add a controller, action, and view for displaying the UI for this example. Ensure that jquery (in this case jquery-1.2.6.js) and jquery.autcomplete.js are referenced at the top of the view (or master page).
Next, add the text box. In this example we will call it city.
<%= Html.TextBox("city") %>
Package this up with a simple controller (Listing 13.1).
Listing 13.1 – a controller & action for displaying our test page
public class HomeController : Controller { public ActionResult Index() { return View(); } }
Figure 13.2 – Our simple view with a text box.
Now we add a little Javascript to add the autocomplete behavior.
Place this in the of the page. You can see that the URL for the autocomplete behavior is specified as Url.Action(“Find”, “City”). This will point to a Find() action on the CityController. We’ll need to write this controller & action next.
Local Data Mode
The autocomplete plugin can also filter local data structures. This is useful when you have a limited set of data and you want to minimize requests sent to the server. The autcomplete plugin in local mode is also much faster, since there is no Ajax request happening behind the scenes. The only downside is that you must render the entire array onto the view.
Listing 13.3 – An action to find cities from an autocomplete ajax request
public class CityController : Controller { private readonly ICityRepository _repository; public CityController() { //load up a CSV file with the city data string csvPath = Server.MapPath("~/App_Data/cities.csv"); //the repository reads the csv file _repository = new CityRepository(csvPath); #2 } //this constructor allows our tests to pass in a fake/mock instance public CityController(ICityRepository repository) #3 { _repository = repository; } //the autocomplete request sends a parameter 'q' that contains the filter public ActionResult Find(string q) #4 { string[] cities = _repository.FindCities(q); //return raw text, one result on each line return Content(string.Join("\n", cities)); } }
The details of the CityRepository can be found in the code samples provided with the book. For now, we will focus on the new Find(string q) action. Since this is a standard action, you can actually just navigate to it in your browser and test it out. Figure 13.3 shows a quick test.
Listing 13.3 – A simple HTTP GET for the action with a filter of “hou” yields the expected results.
Now that we are sure that the action is returning the correct results, we can test the textbox. The Javascript we added earlier hooks up to the keypress events on the textbox and should issue queries to the server. Figure 13.4 shows this in action.
Figure 13.4 – The results are display in a
- tag. We can apply CSS to make it look nicer.
The drop down selections are unformatted by default, which makes them a little ugly. A little CSS magic will make it look much nicer. Listing 13.4 shows some sample CSS for this.
Listing 13.4 – CSS used to style the autocomplete results
<style type="text/css"> div.ac_results ul { margin:0; padding:0; list-style-type:none; border: solid 1px #ccc; } div.ac_results ul li { font-family: Arial, Verdana, Sans-Serif; font-size: 12px; margin: 1px; padding: 3px; cursor: pointer; } div.ac_results ul li.ac_over { background-color: #acf; } style>
Figure 13.5 – The styled dropdown results look much nicer. The selected item is highlighted, and can be chosen with the keyboard or the mouse.
The auto-complete plug-in has many options for you to configure to your needs. For the simple case that we’ve shown here, it’s as simple as this:
$(your_textbox).autocomplete('your/url/here');
Other options for the plugin are listed below:
inputClass | This class will be added to the input box. |
resultsClass | default value: “ac_results” |
loadingClass | The class to apply to the input box while results are being fetched from the server. Default is “ac_loading.” |
lineSeparator | Default is \n |
minChars | The minimum # of characters before sending a request to the server. Default is 1. |
delay | The delay after typing when the request will be sent. Default is 400ms. |
There are many more options, but these are some common ones. To set these options, you include them in a dictionary as the second argument to the autocomplete method like this:
$("input#city").autocomplete('<%= Url.Action("Find", "City") %>', { minChars : 3, delay : 300 });
This type of functionality is immensely useful for selecting from large lists. It keeps your initial page size down by not loading all of these items at once and is very user-friendly.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.