The dynamic tag helper prototype is getting richer in functionality, in this post we are going to add support for text fields auto-completion.
When a user is inputting text in a text field, auto-complete allows the user to select text from a list of suggestions. The suggestions are updated as the user is typing in order to display the most relevant possibilities.
This feature can be observed in most search boxes all over the internet, consider google’s search box for example:
Thanks to auto-complete, when searching for “Italian pizza recipes”, the user can avoid typing the whole query into the search box. Simply typing “Italian pizza” will bring some suggestions containing “Italian pizza recipes” that the user can select.
We are going to see how our dynamic form tag helper supports this. Full code is available in the Github repository.
Setting up auto-complete for a text input field?
One way to implement auto-complete for a form text field is to place a list element
<ul> somewhere under the
Then, it is possible to register a key press listener on the
<input> element that will populate the list with relevant suggestions for each key stroke as the
<input> field is getting filled.
For each key press, the listener fetches the content of the
<input> field and searches inside a suggestions source for strings containing or starting with the typed characters. It then updates the content of the suggestion list, take a look at the following animation from this johnjohnston.info post:
In addition, a modern auto-complete solution must provide an acceptable user experience by highlighting the selected suggestions and by allowing to select a suggestion via keyboard(arrow keys and Enter).
For our prototype, we are going to use the Typeahead.js front-end library which we will talk about further but first let’s see how to activate auto-complete for a specific class property on the server side.
Enabling auto-completion with the AutoComplete attribute
Activating auto-complete for a specific
string property on a given view model class is just a matter of slapping the
[AutoComplete] attribute on it, as we can see in the following snippet:
[AutoComplete] attribute contains two notable properties:
SuggestionsPropertythat allows to specify the name which is a read-only
List<string>property representing the suggestion source that is going to be made available as a local source on the client side.
SuggestionsEndpointthat allows to specify the path of an http endpoint that is going to be used on the client side to query for the list of suggestions.
Consider the following snippet, where the
SuggestionsEndpoint property is used:
Queries for dog names suggestions will be directed to the
/Home/DogNames endpoint which leads to the following action on the
The previous action method takes a
string of typed characters as an argument, so it will be used, for instance, as follows:
You can see that it is responsible for returning a list of strings matching the given typed characters as a JSON.
How this works?
History based suggestion on the generated form has been disabled by adding the
autocomplete="off" html attribute to the generated
<form> element.It has been disabled so it does not conflict with our auto-completion.
FormGroupBuilder is the class responsible for generating the actual form by leveraging the metadata available on the given view model. This class has been modified to detect the
When it detects an
[AutoComplete] attribute on a given property it makes sure that the resulting
<input> element has the
autocomplete css class then depending on the type of suggestions(local or remote) it makes sure that the relevant html attribute is present in the resulting
The relevant html attribute is one of these two:
data-source-localwhich will contain the suggestion source which will be usually an array of strings.
data-source-ajaxwhich will contain the suggestions endpoint as described earlier.
On the client side, the
autocomplete class, the
data-source-ajax attributes are going to be used to enable auto-completion.
Achieving Auto-complete with Typeahead.js
All we have to do is to include the library(usually in the
Shared/_Layout.cshtml view) and call the
typeahead function on the relevant
The previous snippet is executed when the page is ready i.e. under the
$(document).ready function to initialize the auto-completion.
Here we selected all the
<input> elements having the
autocomplete css class, then for each element we apply the
typeahead function with some options.
The first argument is an object in which we specify for example that suggestion highlighting must be enabled.
In the second argument we specify the suggestions source via the
suggestionsEngine is actually a
Bloodhound object; Bloodhound is the suggestion engine used by Typeahead.js, it can handle local and remote sources as well as suggestions caching and pre-fetching.
The following snippet contains the creation of two
Bloodhound objects, the first is configured with a local suggestion source and the second is configured with a remote one:
Bloodhound object involves supplying some tokenizers, I suspect they are used to split the typed characters into distinct words. Then we can set an array of strings as a local source or an object containing a template url of the remote endpoint containing a wildcard that is going to be replaced by the typed characters(
%QUERY in the previous example).
To sum it up, in order to use Typeahead.js for autocompletion we perform the following steps:
- include the Typeahead library
- For each
<input>needing auto-complete we call the
typeaheadfunction by supplying an appropriate suggestion source
This is sufficient to display the suggestions when typing in the relevant fields, the only catch is that the suggestion list is not styled so you will probably need to crank out some css.
In our prototype the initialization of the auto-complete field is done under the
intializeAutoComplete function under the
site.js file, I invite you to take look at it in the Github repository along with the
site.css file if you want to see how things are put together.
DogViewModel.Name properties have been slapped with
[AutoComplete] attribute which yields the following behavior:
Most of the effort in implementing auto-complete lies on the client side, it is crucial to use a good library or to build a good one from scratch if it is more appropriate.
The current prototype imposes the usage of Typeahead.js, it would be better to give the developer the possibility to use an alternative, maybe self made, library for auto-completion.
We can also leverage pre-fetching and caching to give faster suggestions and to minimize queries to the server when using a remote suggestion source.