Partial Page Update with AJAX in Razor Pages

Partial Pages consist of fragments of HTML and server-side code to be included in any number of pages or layouts. Partial pages can be used to break up complex pages into smaller units, thereby reducing the complexity and allowing teams to work on different units concurrently. They can also be used to provide content for updating part of the rendered web page via AJAX in client side script.

A partial page is a single .cshtml file. It has no PageModel and it doesn't have an @page directive at the top. A partial can be strongly typed - have an @model directive, or it can work purely with ViewData. The following examples are based on strongly typed partials which is considered best practice.

The example features the same ICarService used in Working with JSON in Razor Pages. A collection of Car objects will be passed to the partial for display, which will be invoked via client-side script:

First, the Car entity:

public class Car
{
    public int Id { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public int Year { get; set; }
    public int Doors { get; set; }
    public string Colour { get; set; }
    public decimal Price { get; set; }
}

The service has one method that conforms to an interface, generating and returning a list of cars:

public interface ICarService
{
    List<Car> GetAll();
}

public class CarService : ICarService
{
    public List<Car> GetAll()
    {
        List<Car> cars = new List<Car>{
            new Car{Id = 1, Make="Audi",Model="R8",Year=2014,Doors=2,Colour="Red",Price=79995},
            new Car{Id = 2, Make="Aston Martin",Model="Rapide",Year=2010,Doors=2,Colour="Black",Price=54995},
            new Car{Id = 3, Make="Porsche",Model=" 911 991",Year=2016,Doors=2,Colour="White",Price=155000},
            new Car{Id = 4, Make="Mercedes-Benz",Model="GLE 63S",Year=2017,Doors=5,Colour="Blue",Price=83995},
            new Car{Id = 5, Make="BMW",Model="X6 M",Year=2016,Doors=5,Colour="Silver",Price=62995},
        };
        return cars;
    }
}

This service is registered with the ASP.NET Core Dependency Injection system so that it can be made available throughout the application:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddTransient<ICarService, CarService>();
}

The partial itself contains an HTML table styled using Bootstrap. It is named _CarPartial.cshtml and is placed in the Pages/Shared folder - that being one of the default search locations for partials in Razor Pages. The model that the partial expects is a List<Car>:

@model List<Car>

<table class="table table-striped">
@foreach(var car in Model)
{
    <tr>
        <td>@car.Model</td>
        <td>@car.Make</td>
        <td>@car.Year</td>
        <td>[email protected]</td>
    </tr>
}
</table>

Most often, the handler method that serves up partials will not be the primary handler method in a specific page. Instead, a named handler will be used. The following code shows a basic PageModel that includes a named handler (OnGetCarPartial) returning a PartialViewResult:

public class AjaxPartialModel : PageModel
{
    private ICarService _carService;
    public AjaxPartialModel(ICarService carService)
    {
        _carService = carService;
    }

    public List<Car> Cars { get; set; }
    public void OnGet()
    {
    }

    public PartialViewResult OnGetCarPartial()
    {
        Cars = _carService.GetAll();
        return Partial("_CarPartial", Cars);
    }
}

Note

The Partial helper method was added to the PageModel class in ASP.NET Core 2.2. In Razor Pages versions up to and including 2.1, you must explicitly create an instance of PartialViewResult and return that from the handler, passing in the current ViewData dictionary and, optionally, a model for the partial (if it expects one):

public PartialViewResult OnGetCarPartial()
{
    Cars = _carService.GetAll();
    return new PartialViewResult {
        ViewName = "_CarPartial",
        ViewData = new ViewDataDictionary<List<Car>>(ViewData, Cars)
    };
}

Here is the content page where jQuery is used to make the AJAX request when the button is clicked:

@page
@model RazorPagesTests.Pages.AjaxPartialModel


<h2>Ajax</h2>
<p><button class="btn btn-primary" id="load">Load</button></p>
<div id="grid"></div>

@section scripts{
    <script>
        $(function () {
            $('#load').on('click', function () {
                $('#grid').load('/ajaxpartial?handler=CarPartial');
            });
        });
    </script>
}

Notice particularly the URL that is passed to the load method - the name of the named handler method (without the OnGet part) is passed to a query string value called handler. If you prefer not to have a query string, you can create a route template in the Razor Page that adds an optional item named handler to the route values:

@page "{handler?}"

This enables you to can pass the name of the handler as a segment of the URL:

$('#grid').load('/ajaxpartial/carpartial');

Here is an alternative version that uses the Fetch API instead of the XMLHttpRequest object via jQuery:

@page
@model RazorPagesTests.Pages.AjaxPartialModel


<h2>Ajax</h2>
<p><button class="btn btn-primary" id="load">Load</button></p>
<div id="grid"></div>

@section scripts{
    <script>
        document.getElementById('load').addEventListener('click', () => {
            fetch('/ajaxpartial?handler=CarPartial')
                .then((response) => {
                    return response.text();
                })
                .then((result) => {
                    document.getElementById('grid').innerHTML = result;
                });
        });
    </script>
}
Last updated: 05/10/2023 08:31:34

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