Posting forms through ajax in any ASP.NET MVC application

This is the fifth blog post in a series of posts that covers how I’ve set up an ASP.NET Core MVC project with Aurelia in a way that will allow me to render razor views and make use of MVC features such as model binding and form validation while at the same time using Aurelia to give the UI that SPA touch that modern web applications of today so often require. The goal is a setup where most experienced ASP.NET MVC Developers can go on and develop their views sort of as always, while the designated front end developer (=me) can leverage Aurelia to enhance the user experience with all sorts of client side features. All the code can be found in this Github repo.

In this post we’ll take a short break from Aurelia and actually only use things that already should be at least somewhat familiar to most ASP.NET MVC developers. In my first post I made all navigation go through aurelias client side routing engine so what we need to do now is to ensure that any forms posted are posted async, a.k.a “through ajax”. Note that everything I cover in this post could be used in any ASP.NET MVC site for forms that you want to post through ajax.

Pre mvc core ASP.NET MVC had a set of HtmlHelpers available on the Ajax property of the view class, such as “Ajax.BeginForm”. In Core these helpers do not exist (the whole Ajax property is gone), but the small javascript library “jQuery Unobtrusive Ajax” is still available and maintained on Github by Microsoft. Having this added to your page enables the use of some data-ajax-* attributes that enables the same functionality you could get from Ajax.BeginForm. Unfortunately I haven’t found any in depth documentation but this GH Issue thread has a rundown of the available attributes and I’ll explain the ones I’ll be using here. We’ll start off with the marker attribute data-ajax=”true”. If you want to follow along, here is the starting point for this post.

To make the solution a bit more DRY we’ll create a TagHelper class called AjaxFormTagHelper. For this version I’ll make the TagHelper target any form tag that has the data-ajax=”true” attribute. This will require all form tags to be marked up with data-ajax=”true” which will make the tag helper a bit more discoverable for any newcomers that joins in on work in the code base. However, you could very well adjust the TagHelper to target all form tags and make it add the data-ajax=”true” automatically.

With the data-ajax marker attribute in place the tag helper is also going to set attributes according to the following:

Attribute Value
data-ajax-method POST
data-ajax-update .razor-load-area
data-ajax-mode replace-with

This means the form will be POSTed and when the server responds the response will replace the element found by the jQuery selector we set in the data-ajax-update attribute. You can see the full TagHelper class here.

So what is this “razor-load-area” css class? Actually we don’t have any element with this class in the page yet, but we’ll fix that by returning to the _Layout.cshtml that we stripped of pretty much everything in the first post. Around the @RenderBody() call we’ll add a wrapper:

<div class=”@FooBar.Web.TagHelpers.AjaxFormTagHelper.WrapperClass“>
     @RenderBody()
</div>

And on that wrapper we’ll actually set the class attribute to the value of an exposed constant in the AjaxFormTagHelper to ensure that the css class used is always synced.

Finally we’ll need to add a form tag around the input fields in our Person.cshtml view and I’ve also added a new action in the Controller that receives the post. This just gives the view a message about when the form was posted, but this is the place where you would handle the form post in the same way as any ASP.NET MVC Application (such as validating and saving stuff).

With all this in place we can now build various views with forms and have them post async to the server.

If you liked this post, please click thumbs up and don’t hesitate to make any comments, questions or other remarks.

Leave a Reply

Your email address will not be published. Required fields are marked *


CAPTCHA Image
Play CAPTCHA Audio
Reload Image