ASP.NET Core 2.2 - Details Modal With JSON Entity
Download KH Authenticator

.NET MAUI App for Windows and Android
Online Registration and Authentication
No Password Or Email Address Required!
Certified Providers
KenHaggerty.Com Users Without Passwords Users With Passwords Users Without IdentityThis 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.
This article continues a series about table functions:
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.
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.
Update 12/30/2021
Announced the ASP.NET Core 6.0 - Demos And Utilities Project. Updated articles, asset and topic links.
Comments(0)