Advanced Basics: Build an ASP.NET Core Dropdown TagHelper with Automatic Postback

In today's post, we present an easy way to perform an automatic postback on dropdowns using TagHelpers

Written by Jonathan "JD" Danylko • Last Updated: • Develop •

HTML code on a laptop screen

TagHelpers in ASP.NET Core/5 provide developers with self-contained logic to build their own tags for HTML. This should excite developers because you can build composite HTML controls on an abstract level.

Over the past week, I was building a simple grid and decided to add a dropdown to group and filter records displayed in the grid. I also added a button to the right of the dropdown so after you select how you want your records filtered, you could press the button and perform the postback to display the records.

Once completed, I examined my rough-cut and thought this would be better as a TagHelper. Not only that, but I realized I could remove the button altogether and perform an automatic postback when the DOM onchange event occurred.

There was one little drawback with the approach.

While TagHelpers are great at providing high-level HTML components, one of the downsides is self-containing JavaScript in a TagHelper. Of course, you can embed the script tag into the component, but it doesn't make sense when you have multiple TagHelpers on a page with numerous script tags everywhere when they should be bundled at the bottom of a web page.

Luckily for this TagHelper, it doesn't require a lot of JavaScript. It only requires an attribute.

In this quick post, we create a simple TagHelper to automatically postback to the server. One additional note is we'll be using Razor Pages with the OnGet/OnPost functionality.

TagHelper Design

In a recent post, I mentioned how to use JavaScript like pepper and just sprinkle JavaScript throughout your application. In this case, it's a simple attribute we're adding to automatically postback the form to the server.

This is essentially what I'm referring to when I say you can use plain HTML and CSS to accomplish the same goal, but provide minimal JavaScript to enhance your application's performance. 

Back to our TagHelper.

Since there is already a SelectTagHelper available, we'll use this existing functionality instead of building something new. We'll call the name of our tag SelectAuto.


The TagHelper is small and easy to write, so let's look at our SelectAuto code and see what it looks like in HTML.

[HtmlTargetElement("SelectAuto")]
public class SelectAutopostTagHelper : SelectTagHelper
{
    public SelectAutopostTagHelper(IHtmlGenerator generator) : base(generator) { }

   public string Form { get; set; } = "forms[0]";

   public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "select";

       base.Process(context, output);

       if (!output.Attributes.ContainsName("onchange"))
        {
            output.Attributes.Add("onchange", $"document.{this.Form}.submit()");
        }
        else
        {
            output.Attributes.SetAttribute("onchange", $"document.{this.Form}.submit()");
        }
    }
}

The HTML for the SelectAuto is even easier. 

<SelectAuto form="myFormName" class="form-select" id="SelectedItem" name="SelectedItem">

The only attribute required for our SelectAuto TagHelper to work is the name of your form. The name of the form should be on your <form> tag.

<form method="post" name="myFormName" id="myFormName">

If you examine the C# code for the TagHelper above, the only reason we need the form name is to allow a postback of the form on an 'onchange' event. When a person selects a different option, it's posts the form back to the server.

While the Form property isn't required, we add a default value on initialization. If you only have one form on the page, we use the JavaScript forms object to grab the first form ("forms[0]") and submit it.

In my code, I have an OnPost event which is bound to a SelectedItem property. On redirect, it passes in the selected item into the OnGet method to grab the corresponding data and prepare it for the view (HTML).

public IActionResult OnPost()
{
    return RedirectToPage("Create/"+SelectedItem);
}

The OnGet method provides the selected item as the parameter 'id'.

public async Task<IActionResult> OnGetAsync(string id = "")

Our TagHelper gives us a simplified version of performing automatic postbacks.

Our webpage would execute in this manner:

  1. On request of the webpage, we don't pass in the id, use a default dropdown value, and prepare our list of options.
  2. The page and TagHelper renders out a simple <select> tag with an onchange event containing our Form name (or default form name) in the JavaScript event.
  3. The user selects a different item from the dropdown.
  4. This triggers the onchange event and posts the form back to the server's OnPost event.
  5. Our OnPost event grabs the selected item from our [bindproperty] on our Razor page and redirects it to the OnGet page.
  6. The OnGet page receives the id as our selected item and loads the data accordingly.

All of this with minimal JavaScript.

Conclusion

In this post, I covered an easy way to encapsulate an automatic postback in a new SelectAuto TagHelper. Of course, you can call the tag whatever you want in the HtmlTargetElement attribute.

Even though this is a small TagHelper, I would consider it as important as the Condition TagHelper.

For additional TagHelper assistance, check out the following posts:

Have you created any TagHelpers? Did you use JavaScript or CSS? Post your comments below and let's discuss.

Did you like this content? Show your support by buying me a coffee.

Buy me a coffee  Buy me a coffee
Picture of Jonathan "JD" Danylko

Jonathan Danylko is a web architect and entrepreneur who's been programming for over 25 years. He's developed websites for small, medium, and Fortune 500 companies since 1996.

He currently works at Insight Enterprises as a Principal Software Engineer.

When asked what he likes to do in his spare time, he replies, "I like to write and I like to code. I also like to write about code."

comments powered by Disqus