How to close Bootstrap modal in Blazor WASM?

Cenk 1,026 Reputation points
2024-06-21T19:34:00.18+00:00

Hi,

In my Blazor WASM (.net 6) application, I am displaying a modal popup as follows.

<!-- Modal -->
<div class="modal fade bg-transparent" id="templatemo_search" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" 
     @ref="modalRef">
    <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
        <form @onsubmit="SearchProducts" class="modal-content modal-body">
            <div class="input-group mb-2">
                <input type="text" class="form-control" id="inputModalSearch" @bind="searchTerm" placeholder="Search ...">
                <button type="submit" class="input-group-text bg-success text-light">
                    <i class="fa fa-fw fa-search text-white"></i>
                </button>
            </div>
        </form>
    </div>
</div>


I wonder how can I close the modal after retrieving Products?

private async Task SearchProducts()
{
    if (!string.IsNullOrWhiteSpace(searchTerm))
    {
        Products = await _productService.SearchProducts(searchTerm);        
    }
}

Can you please advise on how I can close the modal after retrieving the products?

Thank you!

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,776 questions
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,664 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,283 questions
0 comments No comments
{count} votes

4 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 71,101 Reputation points
    2024-06-21T21:18:48.4333333+00:00

    you don't show the display code. typically you either remove the fade class, or add style="display:block;". you either add fade class or remove style.

    note: the display should be done via Blazor code, not the bootstrap.js file (which you should not include with Blazor apps). the Blazor modal component should has a show property that is set by the parent component.


  2. SurferOnWww 3,816 Reputation points
    2024-06-22T02:46:26.8+00:00

    Can you please advise on how I can close the modal after retrieving the products?

    How about:

    (1) Add button like below to your modal and click it,

    <button type="button" 
      class="btn btn-secondary" 
      data-bs-dismiss="modal">
      Close
    </button>
    

    or

    (2) Use javascript mothods as shown below?

    let divModal = document.getElementById('templatemo_search');
    let myModal = new bootstrap.Modal(divModal);
    
    myModal.show();
    
    myModal.hide();
    

    As @Bruce (SqlWork.com) mentioned in his comment below, myModal.hide(); of item (2) in my answer above does not work in Blazor WASM.

    Sorry about oversight. myModal.hide(); of item (2) in my answer above works when the reference to modal is properly obtained. See exampleJsInterop.js below for correction.

    However, item (1) can close the modal as expected. Shown below is sample. Blazor WASM project created using the template of Visual Studio 2022 version 17.12.2 is used. Target framework is .NET 9.0.

    exampleJsInterop.js

    //window.showBootstrapModal = () => {
    //    let divModal = document.getElementById('staticBackdrop');
    //    let myModal = new bootstrap.Modal(divModal);
    //    myModal.show();
    //}
    
    //window.closeBootstrapModal = () => {
    //    let divModal = document.getElementById('staticBackdrop');
    //    let myModal = new bootstrap.Modal(divModal);
    //    myModal.hide();
    //}
    
    // closeBootstrapModal method above does not work because 
    // myModal obtained in closeBootstrapModal method is 
    // different from myModal in showBootstrapModal method.
    
    // Correction:
    // Modal can be closed by closeBootstrapModal method 
    // once Modal has been opened by showBootstrapModal method.
    
    let myModal;
    
    window.showBootstrapModal = () => {
        let divModal = document.getElementById('staticBackdrop');
        myModal = new bootstrap.Modal(divModal);
        myModal.show();
    }
    
    window.closeBootstrapModal = () => {
        if (myModal != undefined) {
            myModal.hide();
        }
    }
    

    index.html

    Script tags are added as shown below. Please note that bootstrap.js is included in the project created using template of Visual Studio.

    enter image description here

    Modal.Razor

    @page "/modal"
    @inject IJSRuntime JSRuntime;
    @inject HttpClient Http
    
    <PageTitle>Bootstrap Modal</PageTitle>
    
    <!-- Modal -->
    <div class="modal fade"
         id="staticBackdrop"
         data-bs-backdrop="static"
         data-bs-keyboard="false" tabindex="-1"
         aria-labelledby="staticBackdropLabel"
         aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"
                        id="staticBackdropLabel">
                        Modal title
                    </h5>
                    <button type="button"
                            class="btn-close"
                            data-bs-dismiss="modal"
                            aria-label="Close">
                    </button>
                </div>
                <div class="modal-body">
                    @if (forecasts == null)
                    {
                        <p><em>Loading...</em></p>
                    }
                    else
                    {
                        <table class="table">
                            <thead>
                                <tr>
                                    <th>Date</th>
                                    <th aria-label="Temperature in Celsius">Temp. (C)</th>
                                    <th aria-label="Temperature in Farenheit">Temp. (F)</th>
                                    <th>Summary</th>
                                </tr>
                            </thead>
                            <tbody>
                                @foreach (var forecast in forecasts)
                                {
                                    <tr>
                                        <td>@forecast.Date.ToShortDateString()</td>
                                        <td>@forecast.TemperatureC</td>
                                        <td>@forecast.TemperatureF</td>
                                        <td>@forecast.Summary</td>
                                    </tr>
                                }
                            </tbody>
                        </table>
                    }
                </div>
                <div class="modal-footer">
                    <button type="button"
                            class="btn btn-secondary"
                            data-bs-dismiss="modal">
                        Close
                    </button>
                    <button type="button" class="btn btn-danger"
                            @onclick="CloseBootstrapModal">
                        Close by JavaScript (does not work)
                    </button>
    
                </div>
            </div>
        </div>
    </div>
    
    <h1>Bootstrap Modal</h1>
    
    <!-- Via JavaScript -->
    <button type="button" class="btn btn-primary"
            @onclick="ShowBootstrapModal">
        Open by JavaScript
    </button>
    
    <br />
    <br />
    
    <!-- Button trigger modal -->
    <button type="button" class="btn btn-primary"
            data-bs-toggle="modal"
            data-bs-target="#staticBackdrop" 
            @onclick="LoadForecastData">
        Launch static backdrop modal
    </button>
    
    @code {
        private WeatherForecast[]? forecasts;
    
        // protected override async Task OnInitializedAsync()
        // {
        //     forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
        // }
    
        private async Task LoadForecastData()
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
        }
    
        public class WeatherForecast
        {
            public DateOnly Date { get; set; }
    
            public int TemperatureC { get; set; }
    
            public string? Summary { get; set; }
    
            public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
        }
    
        private async Task ShowBootstrapModal()
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
            await JSRuntime.InvokeVoidAsync("showBootstrapModal");
        }
    
        // this does not work
        private async Task CloseBootstrapModal()
        {
            await JSRuntime.InvokeVoidAsync("closeBootstrapModal");
        }
    }
    

    Result

    Model can be closed by cliking [Close] botton or X icon. Modal can also be closed by clicking [Close by JabaScript (does not work)] button once Modal has been opened by showBootstrapModal method.

    enter image description here


  3. Ping Ni-MSFT 4,815 Reputation points Microsoft Vendor
    2024-06-24T08:26:42.6633333+00:00

    Hi @Cenk,

    I suggest you create a small and reuseable ModalDialogComponent.

    1.Create a component named ModalDialog.razor

    <div class="modal @modalClass" tabindex="-1" role="dialog" style="display:@modalDisplay; overflow-y: auto;">
        <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">@Title</h5>
                    <button type="button" class="btn-close" data-dismiss="modal" aria-label="Close" @onclick="Close">
                    </button>
                </div>
                <div class="modal-body">
                    @ChildContent
                </div>
            </div>
        </div>
    </div>
    @if (showBackdrop)
    {
        <div class="modal-backdrop fade show"></div>
    }
    @code {
        [Parameter]
        public string Title { get; set; }
        [Parameter]
        public RenderFragment ChildContent { get; set; }
        private string modalDisplay = "none;";
        private string modalClass = string.Empty;
        private bool showBackdrop = false;
        public void Open()
        {
            modalDisplay = "block";
            modalClass = "show";
            showBackdrop = true;
        }
        public void Close()
        {
            modalDisplay = "none";
            modalClass = string.Empty;
            showBackdrop = false;
        }
    }
    

    2.Use the component in your main razor file

    @page "/"
    @inject ProductService _productService;
    
    <button class="btn btn-primary" @onclick="() => ModalDialog.Open()">Click me!</button>
    <ModalDialog @ref="@ModalDialog" Title="Hello World">
        <form @onsubmit="SearchProducts" class="modal-content modal-body">
            <div class="input-group mb-2">
                <input type="text" class="form-control" id="inputModalSearch" @bind="searchTerm" placeholder="Search ...">
                <button type="submit" class="input-group-text bg-success text-light">
                    <i class="fa fa-fw fa-search text-white"></i>
                </button>
            </div>
        </form>
    </ModalDialog>
    @code {
        private ModalDialog ModalDialog { get; set; }
        private ElementReference modalRef;
        private string searchTerm;
        private List<Product> Products;
        private async Task SearchProducts()
        {
            if (!string.IsNullOrWhiteSpace(searchTerm))
            {
                Products = await _productService.SearchProducts(searchTerm);
                ModalDialog.Close();
            }
        }
       
    }
    

    If you do not want make the modal as a reuseable component, use the following code:

    @page "/"
    @inject ProductService _productService;
    <button type="button" @onclick="() => Open()" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#templatemo_search">Search</button>
    <div class="modal @modalClass" style="display:@modalDisplay; overflow-y: auto;"  id="templatemo_search" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"
         @ref="modalRef">
        <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
            <form @onsubmit="SearchProducts" class="modal-content modal-body">
                <div class="input-group mb-2">
                    <input type="text" class="form-control" id="inputModalSearch" @bind="searchTerm" placeholder="Search ...">
                    <button type="submit" class="input-group-text bg-success text-light">
                        <i class="fa fa-fw fa-search text-white"></i>
                    </button>
                </div>
            </form>
        </div>
    </div>
    @code {
        private string modalDisplay = "none;";
        private string modalClass = string.Empty;
        private bool showBackdrop = false;
        private ElementReference modalRef;
        private string searchTerm;
        private List<Product> Products;
        public void Open()
        {
            modalDisplay = "block";
            modalClass = "show";
        }
        private async Task SearchProducts()
        {
            if (!string.IsNullOrWhiteSpace(searchTerm))
            {
                Products = await _productService.SearchProducts(searchTerm);
                modalDisplay = "none";
                modalClass = string.Empty;
            }
        }
       
    }
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Rena

    0 comments No comments

  4. Robert Haken 1 Reputation point MVP
    2024-11-26T13:49:21.5866667+00:00

    Take a look at HxModal, free full-featured implementation of Bootstrap Modal for Blazor.

    There is a full source-code available for your inspiration: https://github.com/havit/Havit.Blazor/tree/master/Havit.Blazor.Components.Web.Bootstrap/Modals

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.