Almost in each modern website project one of the feature is suggesting user possible items to select when he start typing one of them. Such functionality is done by using control named autocomplete. Under the hood it consists of at least three elements:
- UI control which allow user to type some text - mainly this in HTML input of text type
- Server-side function which serves data to be auto-completed
When we think about creating autocomplete control in ASP.NET MVC 4 we definitely should take a look at jQueryUI framework. One of the feature of this framework is autocomplete control which enables users to quickly find and select from a pre-populated list of values as they type, leveraging searching and filtering. That sounds very good and is excellently what we are looking for.
|Picture 1. Creating MVC 4 project.|
First think we need to add to our solution in our custom model which will store information for view. The assumption here is we want to create two auto-completes that will be part of new AdminController. First one will be responsible for auto-completing car brand and the second will help with choosing proper globalization. Based on this information we can create our first class model which will be located in ~/Models/Admin/ManageModel.cs .Our model will store ifnroation about SelectedCarBrandId and culture Id - very simple.
For C# beginners worth to explain is type of the SelectedCarBrandId - this is int?. Integer is value type so this mean that has default value assigned after declaration (0 at this case). To allow put null value to object of integer type we need to declare our type as Nullable<T> struct and this is equals with the int? syntax. Thanks doing that we can type int? integerValue = null;
After we done with model, now it`s time for creating new controller (in ~/Controller/AdminController.cs). Creating new controller cause that we have new route value available (http://localhost/Admin/) in our project but there is no view to present. But focus at the controller first. Our AdminController containts two function and both of them returns ActionResults (read - returns view). Name of this function is also the same (so we can expect new action available on website http://localhost/Admin/Manage) but whole signature is different. First of all second fuction takes model as parameter and additionally is decorated with HttpPostAttribute . The reason why it is done in that way is difference between how to get this two action. When user open page under the hood uses GET request without any parameters (in this case). Then he changing something on the website and click the submit button - it causes POST request and sends HTML form to the server. That is why we have two function where first (GET) function just render the view and the second (POST) process provider by user data (this data is binded to the model of the ManageModel type at this case).
Next step is create a simple view to display UI for the user. Our view, called Manage.cshtml (picture 2.) will be stored in the following location ~/Views/Admin/Manage.cshtml and will take main layout from parent page which in this case will be _Layout.cshtml.
|Picture 2. Adding view with default layout.|
Now it`s time for achieve our goal and introduce auto-completes controls. Before we do that we need make sure that we provided model for our view already (we want to use ManageModel for Manage view) which allow us to work with a strongly typed view later. Making such connection is quite easy and its noting else then putting namespace declaration for model and calling model type with a @model directive (line 1 and 2 above). Next we switch to implementation of our helper method which will extend standard HtmlHelper by adding new extension function with partial signature MvcHtmlString AutocompleteFor<TModel, TValue>. The most important thing in the function signature is that it takes model type (TModel) and by expression also takes model properties as TValue. Method has two overloaded definition (simple and more advance) but in both cases the most important thing is actionUrl parameters which defines controller action which will be called when user types more then two characters into auto-complete (will be introduced later).
In the implementation above both function calls the same method in the function body. That function is responsible for creating HTML tags for auto-complete control based of passed parameters. There is several important places inside this function that is worth to discuss:
- line 49: contains adding attribute for the input control that will be kind of representative for auto-complete control in whole solution.
- line 50: URL action to be called after user typed more then two characters in control.
- line 66: creating <input type='hidden' /> for storing value (not label) selected by user from auto-complete. Name of the value is equal to the property name indicated in expression (field of the model). This also set default value based on model value.
- line 68: add to the auto-complete attribute which will store name of the associated hidden control.
- url: action on the controller.
- dataType: set as jSon.
- data: provided by the user text inside the control which will be used to filter the result set.
- success: process the response and fill suggestion list
We almost done and our solution is almost ready. We heed to complete just several step more:
2) Create two AdminController methods that will provide data for auto-completes. Remember here that parameter name have to be equals 'query' and jSon result must AllowGet.
3) Add our auto-complete extension function to the view and provide required parameters:
- Model property indicated by the expression
- Controller function generated by Action.
4) Run the solution and go to the http://localhost:port/Admin/Manage and feel free to test.
Source code is available here.