受欢迎的博客标签

Deleting records in ASP.NET Core using AJAX with partial page refresh

Published

This works fine, but there are scenarios where you may want to display different content depending on whether the page contains records or not. In the current scenario, when there are no customers to display, the page will just display an empty grid:

Empty grid with no customers

It would be better to display an empty state which informs the user that there are no customers and allow them to click on a button to add a new customer:

Empty state with status message and button

Since the logic deciding whether to render the grid or an empty state happens on the server, the current approach of simply deleting the rows from the table using JavaScript will not work. Instead, we will need to render that section of the page on the server every time a customer is deleted, and then update the HTML on the client side.

Changing the view

The first thing to do is to extract the logic that renders the card containing the customer grid to a partial view called _CustomerList.cshtml. Note that the partial view was also update with logic to render different content depending on whether there are any customers or not.

If there are no customers, we will render a message to the user and display a button they can click to add a new customer. Otherwise, the list of customers will be displayed, same as last time.

The other major change is that we removed the data-ajax-success attribute from the form and replaced that with a data-ajax-update attribute. This attribute contains the reference to the HTML element which content should be updated with the content returned from the Ajax call. In this case, I state that the content of the div with the ID CustomerList should be updated (we’ll add this code in a moment).

<!-- _CustomerList.cshtml -->
@using DemoApp.Data
@model List<Customer>

<div class="card mt-5">
    <div class="card-header">
        <div class="row align-items-center">
            <div class="col">
                <h4>
                    Customers
                </h4>
            </div>
        </div>
    </div>
    <div class="card-body">
        @if (Model.Count == 0)
        {
            <div class="row justify-content-center text-center">
                <div class="col-12 col-md-10 mt-5">

                    <i class="fa fa-user fa-5x mb-5"></i>

                    <h2>
                        No Customers
                    </h2>

                    <p class="text-muted">
                        You do not have any customers yet. Add a new customer by clicking the <strong>Add Customer</strong> button below.
                    </p>
                    
                    <a class="btn btn-lg btn-primary d-none d-md-inline-block mt-3" href="#">Add Customer</a>
                </div>
            </div> <!-- / .row -->
        }
        else
        {
            <ul class="list-group list-group-lg list-group-flush list my--4">
                @foreach (var customer in Model)
                {
                    <li class="list-group-item px-0">
                        <div class="row align-items-center">
                            <div class="col-auto">
                                <span class="avatar avatar-lg">
                                    <img src="@customer.Avatar" alt="" class="avatar-img">
                                </span>
                            </div>
                            <div class="col ml--2">
                                <h4 class="card-title mb-1">
                                    <a href="#!">@GetCustomerFullName(customer)</a>
                                </h4>
                                <p class="card-text small text-muted mb-1">
                                    @customer.EmailAddress
                                </p>
                            </div>
                            <div class="col-auto">
                                <form asp-action="Delete" asp-route-id="@customer.Id" data-ajax="true" data-ajax-update="#CustomerList">
                                    <button type="submit" class="btn btn-sm btn-danger d-none d-md-inline-block">
                                        Delete
                                    </button>
                                </form>
                            </div>
                        </div>
                    </li>
                }
            </ul>
        }
    </div>
</div>

@functions {
    string GetCustomerFullName(Customer customer)
    {
        return $"{customer.FirstName} {customer.LastName}";
    }
} 

Let’s update the main view to now call the partial view. Also not that I am rendering the partial view inside a divcalled CustomerList. As stated above, the content of this div will be replaced with the content that is returned from the server when a user is deleted because I supplied a reference to this in the partial view in the data-ajax-updateattribute of the form.

@using DemoApp.Data
@model List<Customer>

@{
    ViewBag.Title = "Customers";
}

<div class="container">
    <div class="row">
        <div class="col">
            <div id="CustomerList">
                <partial name="_CustomerList" model="Model"/>
            </div>
        </div>
    </div>
</div>

Updating the controller

We will also need to update the controller. Previously, when a user deleted a customer we simply returned no content. This time around, we will render the _CustomerList partial and return the result of that.

public class Scenario2Controller : Controller
{
    private readonly Database _database;

    public Scenario2Controller(Database database)
    {
        _database = database;
    }

    public IActionResult Index()
    {
        return View(_database.Customers);
    }

    [HttpPost]
    public IActionResult Delete(int id)
    {
        _database.Customers.RemoveAll(customer => customer.Id == id);

        return PartialView("_CustomerList", _database.Customers);
    }
}

Trying it out

With all of that in place, it is time to try it out. In the small screencast below you will notice me deleting customers, and once the last customer is deleted, the page will display the “empty state” content correctly:

Delete a record with partial page refreshplay

Conclusion

In this blog post, I showed how you can return a partial result when deleting a record using Ajax. It is a relatively simple process which can be added to an existing code base and does not require you to go all-in on any of the modern JavaScript frameworks.

Source code is available at https://github.com/jerriepelser-blog/aspnetcore-ajax. Have a look at the Scenario 2controller and views.