Posting Forms with AJAX in Razor Pages

AJAX is a technique used for making asynchronous requests from the browser to the server for various purposes including posting form values. This section covers asynchronous form submission from a Razor Page using both the jQuery AJAX capability and the Fetch API.

The Razor Page

The PageModel for this example includes a property called InputModel, which encapsulates the values to be bound when the form is posted:

public class IndexModel : PageModel
{
    [BindProperty]
    public InputModel Input { get; set; }

    public void OnPost()
    {

    }
}

public class InputModel
{ 
    [Display(Name="First Name")]
    public string FirstName { get; set; }
    [Display(Name = "Last Name")]
    public string LastName { get; set; }
    [EmailAddress]
    public string Email { get; set; }
    [Display(Name = "Date of Birth"), DataType(DataType.Date)]
    public DateTime DateOfBirth { get; set; }
}

The InputModel properties make use of attributes to control the output of tag helpers, specifically the label and input tag helpers.

Here is the content page, styled using BootStrap 4:

<form method="post" class="col-sm-6">
    <div class="form-group row">
        <label asp-for="Input.FirstName" class="col-sm-3 col-form-label"></label>
        <div class="col-sm-7">
            <input asp-for="Input.FirstName" class="form-control">
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Input.LastName" class="col-sm-3 col-form-label"></label>
        <div class="col-sm-7">
            <input asp-for="Input.LastName" class="form-control">
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Input.DateOfBirth" class="col-sm-3 col-form-label"></label>
        <div class="col-sm-7">
            <input asp-for="Input.DateOfBirth" class="form-control">
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Input.Email" class="col-sm-3 col-form-label"></label>
        <div class="col-sm-7">
            <input asp-for="Input.Email" class="form-control">
        </div>
    </div>
    <div class="form-group row">
        
        <div class="col-sm-7 offset-sm-3">
            <button class="btn btn-primary" id="submit">Submit</button>
        </div>
    </div>
</form>

AJAX Forms in Razor Pages

Using jQuery

The first example looks at using jQuery to post the form content asynchronously. The actual script is included using a Razor section, but can just as easily be included in a separate file:

@section scripts{ 
<script>
    $(function () {
        $('#submit').on('click', function (evt) {
            evt.preventDefault();
            $.post('', $('form').serialize(), function () {
                alert('Posted using jQuery');
            });
        });
    });
</script>
}

The jQuery library includes a number of wrapper functions that result in a minimal amount of code required to make an AJAX request. The post function takes care of initialising the XMLHttpRequest object and setting the correct method for the request. This example will post to the current URL because the url parameter is left empty. The data to be posted is constructed using the serialize method, which takes care of retrieving all form values - including the request verification token - and encoding them correctly.

Unobtrusive AJAX

This example uses the Unobtrusive AJAX library which is part of ASP.NET Core and is an add-on to jQuery. It is designed to minimise the amount of script you need to write to handle AJAX requests. Unobtrusive AJAX relies on custom HTML5 data- attributes being applied to the form. So the HTML for the opening form tag is altered as follows:

<form method="post" class="col-sm-6" data-ajax="true" data-ajax-method="post" data-ajax-complete="completed">

The data-ajax-completed attribute references a callback function named completed defined in the scripts section:

@section scripts{ 
<script>
    completed = () => {
        alert('Posted using Unobtrusive AJAX');
    };
</script>
}

Using Fetch

The Fetch API is supported by all modern browsers except Internet Explorer. It is supported by the new Edge browser from Microsoft, which is available on Windows 10. This example makes no use of the jQuery library at all, relying on pure JavaScript:

@section scripts{ 
<script>
    document.forms[0].onsubmit = () => {
        let formData = new FormData(document.forms[0]);
        fetch('', {
            method: 'post',
            body: new URLSearchParams(formData ) 
        })
        .then(() => {
            alert('Posted using Fetch');
        });
        return false;
    };
</script>
}

This example uses the FormData API to construct a set of key/value pairs representing the form fields and their values. The FormData constructor will accepts an HTML form element and then use the name property of each element in the form for the keys and their submitted value for the values.

The FormData object is passed to an instance of URLSearchParams, an object that changes the content-type of the request from multipart/formdata (the default for FormData) to application/x-www-form-urlencoded, which is the correct type for posting simple text/ ASCII data. It should be pointed out that you can leave the content-type as multipart/form-data. Simple text inputs will still be bound to PageModel properties by the model binder.

XMLHttpRequest

For completeness, here is the script for a version that uses the XMLHttpRequest object without any third party libraries:

@section scripts{ 
<script>
    document.forms[0].onsubmit = () => {
        let formData = new FormData(document.forms[0]);
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (this.readyState === 4 && this.status === 200) {
                alert('Posted using XMLHttpRequest');
            }
        };
        xhr.open('post', '', true);
        xhr.send(new URLSearchParams(formData));
        return false;
    };

</script>
}

Further reading

Last updated: 9/19/2018 8:44:51 AM

© 2018 - 2024 - Mike Brind.
All rights reserved.
Contact me at Mike dot Brind at Outlook.com