DEV Community

Cover image for Bootstrap 5 dialogs for ASP .NET Core/C# using ChatGPT
Karen Payne
Karen Payne

Posted on

1

Bootstrap 5 dialogs for ASP .NET Core/C# using ChatGPT

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.

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

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

</div>

<!-- Modal see index1 and index2 which share a common dialog in a partial view -->
<div class="modal fade"
     id="confirmModal"
     data-bs-backdrop="static"
     tabindex="-1"
     aria-labelledby="confirmModalLabel"
     aria-hidden="true">

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

        <div class="modal-content ">

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

                <div class="modal-header">

                    <h5 class="modal-title"
                        id="confirmModalLabel">
                        Please Confirm
                    </h5>

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

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

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

                    <button type="submit"
                            name="answer"
                            value="true"
                            class="btn btn-primary">
                        Yes
                    </button>
                </div>

            </form>

        </div>

    </div>

</div>

@if (Model.UserResponse.HasValue)
{
    <div class="alert alert-info mt-3 text-center">
        You clicked: <strong>@(Model.UserResponse.Value ? "Yes" : "No")</strong>
    </div>
}
Enter fullscreen mode Exit fullscreen mode

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 });
    }
}
Enter fullscreen mode Exit fullscreen mode

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)

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

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

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

            <div class="modal-content">

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

                <div class="modal-body">
                    @Model.Message
                </div>

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

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

            </div>

        </div>

    </div>

</form>
Enter fullscreen mode Exit fullscreen mode

Index1 frontend code

<h1 class="text-center">Delete customer</h1>


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

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

<!-- Render modal with context -->
<partial name="_ConfirmModal" model="(Model.ConfirmationMessage, Model.ConfirmationAction, Model.ConfirmationItemId)" />

@if (Model.UserResponse.HasValue)
{
    <div class="alert alert-info mt-3">
        Action: <strong>@Model.LastActionName</strong><br />
        Item ID: <strong>@Model.LastItemId</strong><br />
        Response: <strong>@(Model.UserResponse.Value ? "Yes" : "No")</strong>
    </div>
}
Enter fullscreen mode Exit fullscreen mode

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
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

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

<h1 class="text-center">Modal dialog</h1>

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

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

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

</div>

<!-- Reuse the modal -->
<partial name="_ConfirmModal" model="@(ValueTuple.Create("Are you sure you want to archive this order?", "ArchiveOrder", Model.OrderId))" />

@if (Model.UserResponse.HasValue)
{
    <div class="alert alert-secondary mt-3 text-center">
        You clicked: <strong>@(Model.UserResponse.Value ? "Yes" : "No")</strong>
    </div>
}
Enter fullscreen mode Exit fullscreen mode

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
        });
    }

}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)