0
votes

I am currently trying to find my way around Blazor Pages.

At the moment I am trying to open a bootstrap model when clicking on a button.

I tried to implement this with a child component (WorkoutsDetail.razor).

However, I don't know what I'm doing wrong, The properties of the model are bind to the input controls using bind-value.

Does anyone have a tip on what else I need to pay attention to?

This is the page where the Button (AddTask) should open the model

@page "/workouts"
@using Tracker.Data
@using Tracker.Services
@inject IWorkoutsListService service
<h3>Workout Plans</h3>
@if (workoutsNames == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Edit</th>
                <th>Delete</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var workouts in workoutsNames)
            {
                <tr>
                    <td>@workouts.Name</td>                  
                    <td><button type="button" class="btn btn-primary" value="Edit">Edit</button></td>
                    <td><input type="button" class="btn btn-danger" value="Delete" /></td>
                </tr>
            }
        </tbody>
    </table>
}
<div>
    <input type="button" data-toggle="modal" data-target="#workoutsModal" class="btn btn-primary" value="Add Task" @onclick="(() => InitializeTaskObject())" />
</div>

<WorkoutsDetail WorkoutObject=workoutObject></WorkoutsDetail>

@code {
    List<Tracker.Data.Workouts> workoutsNames;
    Tracker.Data.Workouts workoutObject = new Tracker.Data.Workouts();
    

    protected override async Task OnInitializedAsync()
    {
        workoutsNames = await service.Get();
    }

    private void InitializeTaskObject()
    {
        workoutObject = new Tracker.Data.Workouts();
        
    }
}

This is where I set the Model

@using Tracker.Data
@using Tracker.Services
@inject IWorkoutsListService service
@inject IJSRuntime jsRuntime

<div class="modal" tabindex="-1" role="dialog" id="workoutsModal" style=" display: block;">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Workout Detail</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">×</span>
                </button>
            </div>
            <div class="modal-body">
                <EditForm Model="@WorkoutObject" OnValidSubmit="@HandleValidSubmit">
                    <div class="form-group">
                        <label for="workoutName">Workout Name</label>
                        <input type="hidden" @bind-value="@WorkoutObject.Id" />
                        <InputText id="name" class="form-control" @bind-Value="@WorkoutObject.Name" />
                    </div>
                    <button type="submit" class="btn btn-primary">Submit</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
                </EditForm>
            </div>
        </div>
    </div>
</div>

@code {

    [Parameter]
    public Tracker.Data.Workouts WorkoutObject { get; set; }

    List<string> TaskStatusList = new List<string>() { "New", "In Progress", "Completed" };

    private async void HandleValidSubmit()
    {

    }

}
3
There are several pure C# alternatives to using the Bootstrap modal which requires bootstrap js and changing the browser DOM outside Blazor. Search "Blazor Modal". - MrC aka Shaun Curtis

3 Answers

0
votes

The way that I achieved this is by using the IJSRuntime and calling the bootstrap method "modal.show" on the desired model and "modal.hide" when I no longer need it:

I started by importing the JSInterop namespace

using Microsoft.JSInterop;

Then I used the InvokeVoidAsync method to call "modal.show"

await JS.InvokeVoidAsync("modal.show", "ConfirmationModal");

This is the HTML:

<div id="@Id" class="modal fade">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <h4 class="modal-title" id="modal-basic-title">@Title</h4>
            <button type="button" class="close" aria-label="Close" @onclick="OnCloseClick">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="modal-body">
            @Body
        </div>
        <div class="modal-footer">
            @Actions
        </div>
    </div>
</div>

Note that the reason why the id is set to @id is because I created a blazor component and reused it throughout by site

0
votes

You can (but don't need to) use JSInterop to open or close modals, when using data-attributes. I use this in my blazor project exactly as you have attempted to do - apart from the following differences:

  1. If you are using the latest version of Bootstrap (V5) - please ensure your data attributes are named correctly:

    data-bs-toggle="modal" data-bs-target="#workoutsModal"

If you leave out the -bs- with Bootstrap V5 it won't work - even though it did work with earlier versions. I also note your modal seems to be based on an older version of Bootstrap. Just ensure that you are following the conventions of the version actually included in your <head> section.

  1. I don't have display: block set for my modal (I don't need any additional styles in order for this to work).
0
votes

I ran your code, it works for me.

Hope you added bootstrap related javascript link in index.html

also remove

style=" display: block;

Gif