Introduction

Learn to use Bootstrap 5.3.4 modal dialogs effectively in ASP.NET Core Razor pages. This means moving modal dialogs out of a page and placing the modal code into a partial view, which accepts parameters to present a confirmation modal dialog.

The second lesson is to use ChatGPT to write the bulk of the code even if a developer has the knowledge to do so. Using ChatGPT to write the bulk of the code saves time and focuses on business logic.

The most important part taught is communication between frontend HTML to backend C# with little code required.

ChatGPT Prompts used

  • For asp.net core, razor pages, no controller, create a Bootstrap 5.3 modal dialog with two buttons yes and no that returns a bool to C# backend

  • To call the modal from your Index.cshtml Razor Page and handle the result in its PageModel (Index.cshtml.cs), here's exactly how you do it — without controllers, staying fully in Razor Pages and Bootstrap 5.3, clean and traditional

  • Create a page for ArchiveOrder – perfect, but code-used tables that are discouraged for accessibility reasons. Asked ChatGPT to use divs and the response was a perfect solution.

  • Throughout each prompt, ChatGPT presented ways to extend each response, which was rejected to keep the code clean for learning purposes.

Shows a model to remove a database record

Pages

There are three Razor pages, the first with modal in the page while the second and third use a partial view.

Index page

The index page code used a modal written on the page. This is standard practice for many developers, which means that each time the same modal is needed for another page, a developer needs to copy and paste code to that page. If a decision is made to modify the modal a developer must make the change for each occurrence of the modal which means that there is room for mistakes.

class="mx-auto p-2" style="width: 200px;">

     class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirmModal">
        Delete Something
    




 class="modal fade"
     id="confirmModal"
     data-bs-backdrop="static"
     tabindex="-1"
     aria-labelledby="confirmModalLabel"
     aria-hidden="true">

     class="modal-dialog  modal-dialog-centered">

         class="modal-content ">

             method="post" asp-page-handler="Confirm">

                 class="modal-header">

                     class="modal-title"
                        id="confirmModalLabel">
                        Please Confirm
                    

                     type="button"
                            class="btn-close"
                            data-bs-dismiss="modal"
                            aria-label="Close">
                

                 class="modal-body">
                    Are you sure you want to continue?
                

                 class="modal-footer">
                     type="submit"
                            name="answer"
                            value="false"
                            class="btn btn-secondary">
                        No
                    

                     type="submit"
                            name="answer"
                            value="true"
                            class="btn btn-primary">
                        Yes
                    
                

            

        

    



@if (Model.UserResponse.HasValue)
{
     class="alert alert-info mt-3 text-center">
        You clicked: @(Model.UserResponse.Value ? "Yes" : "No")
    
}

Backend

public class IndexModel : PageModel
{
    [BindProperty]
    public bool? UserResponse { get; set; }

    public void OnGet(bool? response)
    {
        UserResponse = response;
    }

    public IActionResult OnPostConfirm(string answer)
    {
        if (bool.TryParse(answer, out var result))
        {
            UserResponse = result;
        }

        return RedirectToPage(new { response = UserResponse });
    }
}

Index1 page

Here a partial view is used for this page and Index2. This means the modal confirmation is in one place under Pages\Shared_ConfirmModal.cshtml

The purpose, ask to delete a record from a database.

Parameters

  • Message, text to display
  • ActionName, used in the calling code which can be used in backend code for decisions on what actions to take
  • ItemId, can be a primary from an EF Core query or way for backend code to process actions.

Bootstrap settings

Bootstrap settings

@model (string Message, string ActionName, int ItemId)

 method="post" asp-page-handler="Confirm">

     class="modal fade" id="confirmModal" data-bs-backdrop="static" tabindex="-1" aria-labelledby="confirmModalLabel" aria-hidden="true">

         class="modal-dialog modal-dialog-centered">

             class="modal-content">

                 class="modal-header">
                     class="modal-title" id="confirmModalLabel">Confirmation
                     type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
                

                 class="modal-body">
                    @Model.Message
                

                 type="hidden" name="actionName" value="@Model.ActionName"/>
                 type="hidden" name="itemId" value="@Model.ItemId"/>

                 class="modal-footer">
                     type="submit" name="answer" value="false" class="btn btn-secondary">No
                     type="submit" name="answer" value="true" class="btn btn-primary">Yes

Index1 frontend code

class="text-center">Delete customer


 class="mx-auto p-2" style="width: 200px;">

     class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirmModal">
        Delete Customer #42
    



 name="_ConfirmModal" model="(Model.ConfirmationMessage, Model.ConfirmationAction, Model.ConfirmationItemId)" />

@if (Model.UserResponse.HasValue)
{
     class="alert alert-info mt-3">
        Action: @Model.LastActionName />
        Item ID: @Model.LastItemId />
        Response: @(Model.UserResponse.Value ? "Yes" : "No")
    
}

The button targets the modal in ConfirmModal using _data-bs-target="#confirmModal".

The if statement determines if the Yes or No button was clicked which is set in the backend code, OnPostConfirm.

public class Index1Model : PageModel
{

    public string ConfirmationMessage { get; set; } = "Do you want to delete this customer?";
    public string ConfirmationAction { get; set; } = "DeleteCustomer";
    public int ConfirmationItemId { get; set; } = 42;

    [BindProperty]
    public bool? UserResponse { get; set; }

    [BindProperty(SupportsGet = true)]
    public string LastActionName { get; set; }

    [BindProperty(SupportsGet = true)]
    public int? LastItemId { get; set; }


    public void OnGet(bool? response)
    {
        UserResponse = response;
    }

    public IActionResult OnPostConfirm(string answer, string actionName, int itemId)
    {
        if (bool.TryParse(answer, out var result))
        {
            UserResponse = result;

            if (result)
            {
                if (DataOperations.RemoveCustomer(itemId))
                {
                    Log.Information("Customer {P1} deleted.", itemId);
                }
            }
            else
            {
                Log.Information("Customer {P1} not deleted.", itemId);
            }

            // Save for feedback
            LastActionName = actionName;
            LastItemId = itemId;
        }

         return RedirectToPage(new
        {
            response = UserResponse,
            lastActionName = LastActionName,
            lastItemId = LastItemId
        });
    }
}

Index 2

Pages\Shared_ConfirmModal.cshtml is reused as used in the above page, index1. Rather than asking permission to delete data, here, the modal is used to ask if an item should be archived.

  • The message changes.
  • The for reason changes is now for archiving rather than delete.
  • And the identifier changes.

Frontend code

class="text-center">Modal dialog

 class="mx-auto p-2" style="width: 180px;">
    Order ID: @Model.OrderId


 class="mx-auto p-2" style="width: 200px;">

     class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#confirmModal">
        Archive Order
    




 name="_ConfirmModal" model="@(ValueTuple.Create("Are you sure you want to archive this order?", "ArchiveOrder", Model.OrderId))" />

@if (Model.UserResponse.HasValue)
{
     class="alert alert-secondary mt-3 text-center">
        You clicked: @(Model.UserResponse.Value ? "Yes" : "No")
    
}

Backend code

public class Index2Model : PageModel
{
    [BindProperty(SupportsGet = true)]
    public int OrderId { get; set; } = 123; // Example ID

    public string ConfirmationMessage { get; set; } = "Are you sure you want to archive this order?";
    public string ConfirmationAction { get; set; } = "ArchiveOrder";

    [BindProperty]
    public bool? UserResponse { get; set; }

    public void OnGet(bool? response)
    {
        UserResponse = response;
    }


    public IActionResult OnPostConfirm(string answer, string actionName, int itemId)
    {
        if (bool.TryParse(answer, out var result))
        {
            UserResponse = result;

            if (result && actionName == "ArchiveOrder")
            {
                DataOperations.ArchiveOrder(itemId);
            }
            else
            {
                Log.Information("Order {P1} not archived.", itemId);
            }
        }

        return RedirectToPage(new
        {
            response = UserResponse,
            orderId = itemId
        });
    }

}

Resources

Bootstrap documentation for modals

Source code 🚀 Visit My GitHub Profile

Summary

In this article, the use of vibe coding has been presented as a walkthrough, allowing ChatGPT to write the bulk of the code for going from a Bootstrap modal coded in a Razor page to moving the modal to a partial view.

Even if only one modal is needed in a project, consider using a partial view, as this cleans up code for the page requiring a modal.

Where to go from here? Before moving to more complex modals whose intent is to collect information using input elements, study the code presented, which will assist in moving forward.

And if ChatGPT is not your AI tool, consider GitHub Copilot or JetBrains AI assistant.

Tips

  • When asking the AI tool for assistance consider attaching existing code for a baseline
  • Be prepared to use secondary prompts if the AI tool gets it wrong.