ASP.NET Core 2.2 - Details Modal With JSON Entity

This article will demonstrate a call to a page handler which returns entity details in JSON. The details are displayed on a Bootstrap modal. I will assume you have created a new ASP.NET Core 2.2 Razor Pages project. I won't use Identity or Individual User Accounts.

The FREE ASP.NET Core 6.0 - Demos And Utilities Project includes a Table Functions Demo. Access to the source code is free for registered users at Manage > Assets.

If we create a page handler, we can use a Bootstrap modal rather than redirect to a page.

Edit Index.cshtml.cs > IndexModel, add the page handler:
public async Task<JsonResult> OnGetDetailsByIdAsync(int id = 0)
{
    if (id == 0)
    {
        return new JsonResult(new { Status = "Failed", Errors = "id = 0" });
    }

    var foodDetails = await _context.Foods
        .Where(f => f.Id == id)
        .Select(f => new Food
        {
            Id = f.Id,
            Name = f.Name,
            FoodType = f.FoodType,
            ColdStore = f.ColdStore,
            Date = f.Date
        })
        .FirstOrDefaultAsync();

    if (foodDetails == null)
    {
        return new JsonResult(new { Status = "Failed", Errors = "Details Not Found" });
    }

    return new JsonResult(new { Status = "Success", foodDetails });
}
Edit Index.cshtml, add the modal:
<div class="modal">
    <div class="modal-dialog">
        <div class="modal-content">

            <!-- Modal Header -->
            <div class="modal-header">
                <h4 class="modal-title">Food</h4>
                <button type="button" class="close" data-dismiss="modal">×</button>
            </div>

            <!-- Modal body -->
            <div class="modal-body">
            </div>

            <!-- Modal footer -->
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
            </div>

        </div>
    </div>
</div>
Edit Index.cshtml, update the details link to a modal button:
<button type="button" class="btn btn-link p-0 details" data-id="@item.Id"
    data-toggle="modal" data-target=".modal">Details</button>
Edit Index.cshtml, add the JavaScript:
@section scripts {
        <script>

        const modalBody = document.querySelector('.modal-body');

        function getDetailsById(id) {

            return fetch('/index?handler=DetailsById&id=' + id,
                {
                    method: 'get',
                    headers: {
                        'Content-Type': 'application/json;charset=UTF-8'
                    }
                })
                .then(function (response) {
                    if (response.ok) {
                        return response.text();
                    } else {
                        throw Error('DetailsById Response Not OK');
                    }
                })
                .then(function (text) {
                    try {
                        return JSON.parse(text);
                    } catch (err) {
                        throw Error('DetailsById Method Not Found');
                    }
                })
                .then(function (responseJSON) {
                    modalBody.innerHTML = '';
                    if (responseJSON.status === 'Success') {
                        var foodDetails = responseJSON.foodDetails;
                        var dl = document.createElement('dl');
                        for (prop in foodDetails) {
                            var dt = document.createElement('dt');
                            dt.textContent = prop;
                            dl.appendChild(dt);
                            var dd = document.createElement('dd');
                            dd.textContent = foodDetails[prop].length === 0 ? 'empty' : foodDetails[prop];
                            dl.appendChild(dd);
                        }
                        var successDiv = document.createElement('div');
                        successDiv.classList.add('alert', 'alert-success');
                        successDiv.appendChild(dl);
                        modalBody.appendChild(successDiv);
                    }
                    else {
                        var dl = document.createElement('dl');
                        for (prop in responseJSON) {
                            var dt = document.createElement('dt');
                            dt.textContent = prop;
                            dl.appendChild(dt);
                            var dd = document.createElement('dd');
                            dd.textContent = responseJSON[prop];
                            dl.appendChild(dd);
                        }
                        var alertDiv = document.createElement('div');
                        alertDiv.classList.add('alert', 'alert-danger');
                        alertDiv.appendChild(dl);
                        modalBody.appendChild(alertDiv);
                    }
                })
                .catch(function (error) {
                    modalBody.innerHTML = '';
                    var alertDiv = document.createElement('div');
                    alertDiv.classList.add('alert', 'alert-danger');
                    alertDiv.textContent = 'Error ' + error;
                    modalBody.appendChild(alertDiv);
                });
        }

        // Wait for the page to load first
        document.addEventListener('DOMContentLoaded', function () {

            //Get a reference to the links on the page
            var details = document.querySelectorAll('.details');
            var dl = details.length;
            for (i = 0; i < dl; i++) {
                details[i].addEventListener('click', function (event) {
                    modalBody.innerHTML = '';
                    var spinnerDiv = document.createElement('div');
                    spinnerDiv.classList.add('spinner-border');
                    spinnerDiv.classList.add('text-alert');
                    spinnerDiv.classList.add('d-flex');
                    spinnerDiv.classList.add('mt-2');
                    spinnerDiv.classList.add('ml-auto');
                    spinnerDiv.classList.add('mr-auto');
                    spinnerDiv.setAttribute('role', 'status');
                    var span = document.createElement('span');
                    span.classList.add('sr-only');
                    span.innerText = 'Loading...';
                    spinnerDiv.appendChild(span);
                    modalBody.appendChild(spinnerDiv);
                    getDetailsById(event.target.dataset.id);
                    return false;
                });
            }

        });

    </script>
}

Build, run and test.

Modal Entity No Format.

The Food class DataAnotations do not get serialized. Let's add a JSON Food model with a Status property.

Edit Entities > Food.cs, add a FoodJsonModel:
public class FoodJsonModel
{
    [JsonProperty(PropertyName = "Status")]
    public string Status { get; set; }
    [JsonProperty(PropertyName = "Id")]
    public int Id { get; set; }
    [JsonProperty(PropertyName = "Name")]
    public string Name { get; set; }
    [JsonProperty(PropertyName = "Food Type")]
    public string FoodType { get; set; }
    [JsonProperty(PropertyName = "Store Cold")]
    public bool ColdStore { get; set; }
    [JsonProperty(PropertyName = "Date")]
    public string Date { get; set; }
}
Edit Index.cshtml.cs > IndexModel, update the page handler:
public async Task<JsonResult> OnGetDetailsByIdAsync(int id = 0)
{
    if (id == 0)
    {
        return new JsonResult(new { Status = "Failed", Errors = "id = 0" });
    }

    var foodDetails = await _context.Foods
        .Where(f => f.Id == id)
        .Select(f => new FoodJsonModel
        {
            Status = "Success",
            Id = f.Id,
            Name = f.Name,
            FoodType = f.FoodType.ToString(),
            ColdStore = f.ColdStore,
            Date = string.Format("{0:MM/dd/yyyy hh:mm tt}", f.Date)
        })
        .FirstOrDefaultAsync();

    if (foodDetails == null)
    {
        return new JsonResult(new { Status = "Failed", Errors = "Details Not Found" });
    }

    return new JsonResult(foodDetails);
}
Edit Index.cshtml, update the JavaScript:
        function getDetailsById(id) {

            return fetch('/index?handler=DetailsById&id=' + id,
                {
                    method: 'get',
                    headers: {
                        'Content-Type': 'application/json;charset=UTF-8'
                    }
                })
                .then(function (response) {
                    if (response.ok) {
                        return response.text();
                    } else {
                        throw Error('DetailsById Response Not OK');
                    }
                })
                .then(function (text) {
                    try {
                        return JSON.parse(text);
                    } catch (err) {
                        throw Error('DetailsById Method Not Found');
                    }
                })
                .then(function (responseJSON) {
                    var dl, dt, dd;
                    modalBody.innerHTML = '';
                    if (responseJSON.Status === 'Success') {
                        dl = document.createElement('dl');
                        for (prop in responseJSON) {
                            dt = document.createElement('dt');
                            dt.textContent = prop;
                            dl.appendChild(dt);
                            dd = document.createElement('dd');
                            dd.textContent = responseJSON[prop].length === 0 ? 'empty' : responseJSON[prop];
                            dl.appendChild(dd);
                        }
                        var successDiv = document.createElement('div');
                        successDiv.classList.add('alert', 'alert-success');
                        successDiv.appendChild(dl);
                        modalBody.appendChild(successDiv);
                    }
                    else {
                        dl = document.createElement('dl');
                        for (prop in responseJSON) {
                            dt = document.createElement('dt');
                            dt.textContent = prop;
                            dl.appendChild(dt);
                            dd = document.createElement('dd');
                            dd.textContent = responseJSON[prop];
                            dl.appendChild(dd);
                        }
                        var alertDiv = document.createElement('div');
                        alertDiv.classList.add('alert', 'alert-danger');
                        alertDiv.appendChild(dl);
                        modalBody.appendChild(alertDiv);
                    }
                })
                .catch(function (error) {
                    modalBody.innerHTML = '';
                    var alertDiv = document.createElement('div');
                    alertDiv.classList.add('alert', 'alert-danger');
                    alertDiv.textContent = 'Error ' + error;
                    modalBody.appendChild(alertDiv);
                })
        }

Build, run and test.

Modal Entity Formatted.
Modal Entity Formatted Mobile.
Update 12/30/2021

Announced the ASP.NET Core 6.0 - Demos And Utilities Project. Updated articles, asset and topic links.

Ken Haggerty
Created 08/19/19
Updated 08/28/22 02:15 GMT

Log In or Reset Quota to read more.

Successfully completed. Thank you for contributing.
Processing...
Something went wrong. Please try again.
Contribute to enjoy content without advertisments.
You can contribute without registering.

Comments(0)

Loading...
Loading...

Not accepting new comments.

Submit your comment. Comments are moderated.

User Image.
DisplayedName - Member Since ?