skip to Main Content

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

2

Answers


  1. 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;
        }
    }
    
    Login or Signup to reply.
  2. @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;
       }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search