Today we will create relatively complicated ASP.NET Core tag helper. It will be a custom drop down list with both server side and client side logic. The result will look like this:
First of all, we need to create the basic ASP.NET Core MVC project with the default routes, single HomeController controller, Index action and corresponding views. I will not pay attention to it now, you can use the demo project that I created on the GitHub to avoid boring typing.
So, now we are ready to begin. I’m sure you know what the tag helper is. Create TagHelpers folder in the solution and the DropDownListTagHelper class there. Inherit it from the TagHelper class fill with following code (I will describe it below):
(Please note that we have also added the HtmlTargetElement class attribute.)
We have created very simple tag helper that will do nothing except displaying the text. But it is good for the start. Let’s test it now. To be able to do that we need to add the view model for our view. Create the ViewModels folder in the solution and the IndexViewModel class there (I prefer to put view models to the subfolders with the same names as the corresponding controllers or Shared for others).
As we are going to display both standard select and our custom drop down list, so our IndexViewModel class should have 2 properties and one shared enumeration of the colors and look like this:
Good. Now we will add some logic to the controller to populate our view model with data and pass it into the view. Create the GetColors method, it will be used to generate the enumeration of the colors:
Modify the controller action. Nothing complicated here, just create the view model instance and initialize its Colors property using our new method:
Now we are ready to add both controls to the view and see the result. Let’s edit our Index.cshtml:
You can see our drop-down-list tag helper there. If you run the application now you will see something like this:
So, now we can concentrate directly on the tag helper development. As we could see above, we need user to initialize 2 properties of our tag helper (For and Items using the corresponding asp-for and asp-items attributes. For is used to provide information about the model and its value (selected drop down list item). Items obviously just holds the drop down list items.
Take a look at the Process method of the DropDownListTagHelper class. It’s time to generate real drop down list HTML instead of the plain text stub:
As you can see, return value of the GenerateDropDownList method is used as the tag helper output. Here is the method itself (our drop down list is just a div element with the corresponding class):
The selected item and the items in the drop down are generated using the same GenerateDropDownListItem method. We use a tag here to allow user to work with our control using the keyboard without need to write additional JavasSript code:
The GenerateDropDownListItems method is very simple. It just iterates through the items passed by the Items property and generates them using the GenerateDropDownListItem method:
Now we need to think about how to send the value selected by a user from client-side to server-side. HTML uses forms and input controls to do that, but our custom control is not a standard one, so this approach will not work automatically. That’s why we generate also a hidden input for our drop down list control. We initialize its value on client-side and it is sent then to the server where is automatically bound to the model by ASP.NET Core:
The other important part is getting current drop down list value from the model. We may have an empty model (for example, when user just opens the page and there is no value selected in the drop down list). In this case, we should display the first value as a selected one. We may have some value stored in the model (for example, if user edits some object and we have to display the previously selected value). And the last option, we may have page with the validation errors, so we have to restore the selected value from the model state to avoid need to select it again each time validation fails. This is the implementation of the GetValue method (First of all, we look at the model state values. If there is no any value there we look the model itself.):
And here is the logic of the selected drop down list item selection. It is quite simple:
It extends jQuery to make it possible to get and set the drop down list value using the standard (for jQuery) val function. Also, defines the click event handlers to handle clicks on the drop down list (to open drop down) and on the items (to set the as the selected ones).
I have created the demo project for this post. Feel free to ask if you have any questions!