X

Building confirm delete dialog on Blazor

Blazor supports communication with JavaScript using JavaScript interop. I used JavaScript interop in Blazor when building confirm delete dialog of my Blazor demo application. This blog post shows how to interact with JavaScript code from Blazor and how to build interactive dialogs.

Source code! This blog post is based on my Blazor demo application. It is simple application for books database with server back-end that demonstrates Blazor features and gives some guidance about how to things on Blazor. Demo application is available in my GitHub repository gpeipman/BlazorDemo.

Confirm delete dialog

I have confirm delete dialog defined in Index view of books database. It is simple Bootstrap dialog and here is how it is defined. It’s actually simple but when having closer look there are some tricks.

<div class="modal" id="myModal">
    <div class="modal-dialog">
        <div class="modal-content">

            <!-- Modal Header -->
            <div class="modal-header">
                <h4 class="modal-title">Confirm delete</h4>
                <button type="button" class="close" data-dismiss="modal">&times;</button>
            </div>

            <!-- Modal body -->
            <div class="modal-body">
                <input type="hidden" id="bookToDeleteField" bind=@DeleteId />
                Are you sure you want to delete book <span id="bookTitleField"></span>?
            </div>

            <!-- Modal footer -->
            <div class="modal-footer">
                <button type="button" class="btn" data-dismiss="modal">Cancel</button>
                <button type="button" class="btn btn-danger" onclick=@DeleteBook>Delete</button>
            </div>

        </div>
    </div>
</div>

Two special things to notice:

  1. bookToDeleteField – it is bound to Blazor variable DeleteId and Blazor takes care of this variable.
  2. Delete button – onclick event is handled by DeleteBook event defined in Blazor.

Opening confirm delete dialog

There is one trick more I don’t like very much but this is how things work right now. Take a look at the books table rendered by Blazor.

<table class="table table-striped">
    <tr>
        <th>Id</th>
        <th>Title</th>
        <th>ISBN</th>
        <th></th>
    </tr>
    @foreach (var book in Books.Results)
    {
        var id = book.Id;
        var title = book.Title;
        <tr>
            <td>@book.Id</td>
            <td>@book.Title</td>
            <td>@book.ISBN</td>
            <td>
                <button class="btn green" onclick="@(() => EditBook(id) )">...</button>
                <button class="btn red deleteBook" onclick="@(() => ConfirmDelete(id, title) )">x</button>
            </td>
        </tr>
    }
</table>

In the beginning of loop we assign booking ID to local variable id. This is because of how click event of Delete button is called. It is action and everything in action body is evaluated when action is called. There is no better way right now for events with arguments. If we use book.Id in actions then book will be evaluated when action call is made and for this point book is always the last one in books list.

ConfirmDelete method is here.

protected void ConfirmDelete(int id, string title)
{
    DeleteId = id;
    RegisteredFunction.Invoke<bool>("confirmDelete", title);
}

We assign book ID to DeleteId variable defined in confirm delete dialog. After this we use JavaScript interop to show the dialog.

Using JavaScript interop

Blazor is not JavaScript but WebAssembly. These two technologies are different but they must be able to communicate with each other. For this we have JavaScript interop in Blazor. We have to register all JavaScript functions we want to call from Blazor.

<script>
    Blazor.registerFunction('confirmDelete', (title) => {
        $('#bookTitleField').text(title);
        $('#myModal').modal('show');

        return true;
    });
</script>

When page that is hosting Blazor application is loaded we register function called confirmDelete to Blazor so it can call it.

Deleting book

When Delete button is clicked in dialog then DeleteBook() method defined in Blazor is called.

protected async Task DeleteBook()
{
    RegisteredFunction.Invoke<bool>("hideDeleteDialog");

    await BooksClient.DeleteBook(DeleteId);
    await LoadBooks(int.Parse(Page));
}

There is one more interop method – hideDeleteDialog – that hides dialog when Delete button is clicked.

<script>
    Blazor.registerFunction('hideDeleteDialog', () =>
{
        $('#myModal').modal('hide');

        return true;
    });
</script>

This is it. We have now modal confirm delete dialog that uses JavaScript interop in Blazor.

Too much code for simple thing?

Registering all JavaScript functions we want to call is not convenient. Just imagine some application having a lot of JavaScript involved. Using Bootstrap components is also good example. hideDeleteDialog() method turns useless if there is one day some simpler way to just call modal() method on #myModal element.

I have seen few attempts to easen the pain but these small components don’t work with current versions of Blazor. Still there are people out there who are trying to invent the ways how to hide interop details behind wrapper methods we can use in Blazor. I am sure that release version of Blazor also provides something to get better interaction between JavaScript and WebAssembly.

Wrapping up

Building confirm delete dialog in Blazor wasn’t that hard. We built regular Bootstrap dialog like many other web applications have. We also used some JavaScript interop from Blazor to be able to control the dialog from Blazor code. We ended up with simple solution that could be even smaller but we can’t complain – Blazor is still experimental non-stable technology under active development and we are using early versions of it. With stable release I hope to see some shortcut methods that invoke JavaScript functions but hide JavaScript interop details from us.

References

Liked this post? Empower your friends by sharing it!
Categories: ASP.NET Blazor

View Comments (5)

  • I have a question -actually a scenario- in my mind. In Blazor, what if I wanted to add a search box and a simple table, whose data is filtered by the search phrase typed in the search box? Without a submit button, it requires a textChanged event to be handled. While there is no Textbox object -and shouldn't exist- the event would most probably be triggered by the bound string -I assume via a custom event handler on the set method of string property. Yet, I am not sure how Blazor would handle it in a proper manner.

    The second is the dynamic table which should be changed by the bound IEnumerable, IQueryable etc. Since the generic table is created by a foreach loop, no matter the bound collection changes, it won't change the html code.

    I assume the both cases require Javascript for both event handling and Ajax-like dynamic changes. I may be wrong, of course. In an architectural point of view, should Blazor include these features? Or should it be handled via Javascript?

  • As modal dialog is implemented by Bootstrap I really don't want to jump in this way to what Bootstrap controls.

  • You can do this without JavaScript

    Set the modal to auto launch the popup and set a variable

    ConfirmDelete(id))">
    Delete

    protected void ConfirmDelete(int id)
    {
    idToDelete= id;
    }

    then in the dialog button

    Delete

    protected async Task DoTheDelete()
    {
    await _someService.Delete(idToDelete);
    }

Related Post