0

I have a Blazor .Net 8 webb app that uses a Bootstrap 5.3 Offcanvas component as a menu of items that can be selected from. When the user chooses the menu item, I want the Offcanvas component to close automatically.

The way I did this was to create a ButtonClicked event that calls the JavaScript like this

`await JS.InvokeVoidAsync("closeOffcanvas");`

This is called right before the OnFilterSelected EventCallback

For the Bootstrap I'm using data-bs attributes. I searched extensively for a solution to no avail. The JavaScript I came up with can be seen below closeOffcanvas.js below). I'm at best a novice java script programmer

Below is the relevant code, for a working example see this GitHub repo

Any help would be appreciative.

closeOffcanvas.js

window.closeOffcanvas = function () {
  var offcanvasElement = document.getElementById("offcanvasid");
  var offcanvas = new bootstrap.Offcanvas(offcanvasElement);
  offcanvas.hide();
};

Filter.razor

<button class="btn btn-primary btn-sm" data-bs-toggle="offcanvas" data-bs-target="#offcanvasid">
  Contents
  <i class="fas fa-bars"></i>
</button>

<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasid">

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

  <div class="offcanvas-body">

    <ul class="list-group">
      @foreach (var item in Enums.MenuItem.List.OrderBy(o => o.Value))
      {
        <li class="list-group-item @ActiveFilter(item)">
          <a @onclick="@(e => ButtonClicked(item))"
             type="button"
             id="@item.ButtonId">
            @item.Value <small>@item.Title</small>
          </a>
        </li>
      }
    </ul>

  </div>
</div>

@code

  [Parameter, EditorRequired] public required Enums.MenuItem? CurrentFilter { get; set; }
  [Parameter] public EventCallback<Enums.MenuItem> OnFilterSelected { get; set; }

  protected Enums.MenuItem currentMenuItem = Enums.MenuItem.HebrewPassOverOrCrossOver;

  private async Task ButtonClicked(Enums.MenuItem filter)
  {
    currentMenuItem = filter;

    // calling this doesn't close the component 
    //   It also disables the close button
    await JS.InvokeVoidAsync("closeOffcanvas"); 

    await OnFilterSelected.InvokeAsync(filter);
  }


// other code

Index.razor

This is the razor page that calls Filter.razor component

@page "/"
<h1>Home</h1>

<div class="d-flex justify-content-end mx-1">
  <Filter CurrentFilter=@CurrentFilter OnFilterSelected="@ReturnedFilter" />
</div>

<!-- Do something with the chosen filter -->

@code

  public MenuItem CurrentFilter { get; set; } = MenuItem.HebrewPassOverOrCrossOver; // default item
  

  private void ReturnedFilter(MenuItem filter)
  {
    CurrentFilter = filter;
    StateHasChanged();
  }
1
  • 1
    Thank you Yogi, this answers my question. I had looked at the bootstrap documentation before but did not appreciate that it was the solution to my problem. I don't need any JavaScript I just needed to add data-bs-dismiss="offcanvas" to my list items. Commented May 7, 2024 at 13:19

2 Answers 2

2

Here's a demo page using the code example from the Bootstrap demo page that shows how to show and hide the off-canvas content directly in c#.

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<div class="m-2">
    <button class="btn btn-primary" @onclick="ToggleCanvas">
        Show Off Canvas
    </button>
</div>

<div class="offcanvas offcanvas-start @_offCanvasCss" tabindex="-1" style="@_offCanvasStyle" role="dialog">
    <div class="offcanvas-header">
        <h5 class="offcanvas-title">Offcanvas</h5>
        <button type="button" class="btn-close text-reset" @onclick="ToggleCanvas"></button>
    </div>
    <div class="offcanvas-body">
        <div>
            Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
        </div>
        <div class="dropdown mt-3">
            <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown">
                Dropdown button
            </button>
            <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
                <li><a class="dropdown-item" href="#">Action</a></li>
                <li><a class="dropdown-item" href="#">Another action</a></li>
                <li><a class="dropdown-item" href="#">Something else here</a></li>
            </ul>
        </div>
    </div>
</div>

@if (!_hideCanvas)
{
    @* Had to set the z-index as the bootstrap version seemed to have it wrong - check yours *@
    <div class="modal-backdrop fade @_offCanvasCss" style="z-index:1040" @onclick="ToggleCanvas"></div>
}
@code{
    public bool _hideCanvas = true;
    public string _offCanvasStyle => _hideCanvas ? "visibility:hidden;" : "visibility:visible;";
    public string _offCanvasCss => _hideCanvas ? "hide" : "show";

    private Task ToggleCanvas()
    {
        _hideCanvas = !_hideCanvas;
        return Task.CompletedTask;
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

This is the better approach because it doesn't use bootstrap.js and you have more control over your component.
2

@Yogi answered my question. I don't need any JavaScript I just needed to add data-bs-dismiss="offcanvas" to my list items. Here's how it should look

  <li class="list-group-item @ActiveFilter(item)">
    <a @onclick="@(e => ButtonClicked(item))"
         type="button" data-bs-dismiss="offcanvas" id="@item.ButtonId">
        @item.Value <small>@item.Title</small>
    </a>
  </li>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.