Guide on programmatically concealing a Bootstrap Offcanvas element using JavaScript and Blazor

In my Blazor .Net 8 web application, I have implemented a Bootstrap 5.3 Offcanvas component as a menu for selecting items. I wanted the Offcanvas to close automatically when a user selects an item from the menu.

To achieve this functionality, I created a ButtonClicked event that triggers the following JavaScript code:

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

This is executed just before the OnFilterSelected EventCallback.

I used data-bs attributes for incorporating Bootstrap. Despite extensive research, I could not find a solution. Below is the JavaScript code I developed in a file named closeOffcanvas.js. Please note that my JavaScript skills are at a novice level.

The relevant code snippet can be found below. For a functional example, you can refer to this GitHub repository.

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></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 Razor page integrates the 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();
  }

Answer №1

@Yogi provided the solution to my query. Instead of using JavaScript, all I had to do was include

data-bs-dismiss="offcanvas"
in my list items. This is how the code should appear:

  <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>

Answer №2

Check out this demonstration page featuring the code snippet from the Bootstrap demo, illustrating how to display and conceal off-canvas content directly in C#.

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, there!</h1>

Discover the functionalities of your new application.

<div class="m-2">
    <button class="btn btn-primary" @onclick="ToggleCanvas">
        Display 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>
            Here is some placeholder text. In reality, you can include various elements such as text, images, lists, and more.
        </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)
{
    @* Adjusted z-index due to a possible error in the bootstrap version - verify 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;
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What causes addEventListener to not return a value?

In this snippet of code: let rockClick = rockBtn.addEventListener('click', playRound.bind("rock", computerPlay(), false)); After using console.log(), the output is undefined. The purpose of rockBtn:const rockBtn = document.querySelecto ...

What is the best way to transfer weather data from a server to an HTML text area box?

Recently, I delved into the world of expressJS to set up a local server (localhost:3000). With the power of JavaScript (specifically in a file named app.js), I was able to send simple messages like "Hello World" to the browser. However, now I find myself f ...

Using Regular Expressions to access a deeply nested object

Within my JS objects, there is a common grandchild property called 'products'. For example: ecommerce.add.products, ecommerce.remove.products, ecommerce.detail.products, ecommerce.checkout.products, ecommerce.purchase.products I am attempting t ...

Unveiling the essence of Lodash's differenceBy functionality

I am facing a challenge with two arrays of objects. I need to identify the differences between the newData and oldData arrays based on their identifiers. Specifically, I want to display objects from oldData whose identifiers are not present in newData. Her ...

Can CSS be used for creating unique color combinations?

I am facing a challenge where I have two div elements with different transparent, colored backgrounds that overlap each other. My goal is to find a way to customize the color in the area where these elements overlap. For instance, if I blend red and blue ...

When should you utilize the Safe Navigation Operator (?.) and when is it best to use the Logical AND (&&) operator in order to prevent null/undefined references?

Imagine having an object property (let's call it arrThatCouldBeNullOrUndefined: SomeObjType) in your Angular component. You aim to perform an array operation (let's say filter() operation) on its data: DataType[] object and save the result in an ...

Improving the efficiency of my conditions in a function with Vue JS

Does anyone have any suggestions on how to optimize this function? I feel like it could be shortened to improve its efficiency. Any help or advice would be much appreciated. Function: onStudentActionSelect: function () { if (this.selectedRows.length ...

"Encountering problems with the form tag with runat server attribute when creating user controls dynamically

I am currently working on generating a user control that includes a label, dropdown menu, and text box dynamically so that I can easily set the value of the label. However, I encountered an issue with the dropdown and textbox because they require a form ta ...

Unsubscribing from a service method in Javascript using RxJS

After clicking a button, a function is triggered to execute. The function includes an method called "executeAction" that retrieves the current view and then passes it as a parameter to another view for future reference. async executeAction(action: ...

If you refer to a function, are you personally calling the function or asking the reference to call it?

From what I understand, and please correct me if I'm mistaken, when a variable is assigned to a function in the form of a function expression, it doesn't hold the function in the same way that it holds a primitive value. The variable simply refer ...

Extracting values from an event in Vue.js: A step-by-step guide

When working with Vue.js, I use the following code to fire an event: this.$emit("change", this.data); The parent component then receives this data, which is in the form of an object containing values and an observer. It looks like this: { data ...

Making changes to an object using a different object

Is it possible to merge one object with another object? For instance master = { name: "John", email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e389a389cd808c8e">[email protected]</a>" } child = { phone: ...

Sending an HTML form to an external ASP script

I am currently attempting to create an HTML form that can submit multiple variables to an external ASP file that generates a chat window. The given example I am working with can be viewed through this link, although it involves a two-step process. In the ...

Choosing a single radio button value within a nested ng-repeat loop in AngularJS

Help needed with selecting only one radio button value in nested ng-repeat. Please review the source code and suggest any potential mistakes. <form ng-submit="save()"> <div ng-repeat="x in surveyLst"> <div class="row"> < ...

Inserting multiple rows of data into a MySQL database in a single page using only one query in PHP

This snippet shows a MySQL query being used to update and insert data into a database: if ($_POST["ok"] == "OK") { $updateSQL = sprintf("UPDATE attend SET at_status=%s, at_remarks=%s WHERE at_tt_idx=%s", GetSQLValueString ...

What could be causing the computed property in Vue 2 component to not return the expected state?

I'm encountering an issue with my Vue component where it fails to load due to one of its computed properties being undefined: Error: Cannot read properties of undefined (reading 'map') Here is the snippet of the computed property causing ...

Yeoman - Storing global settings efficiently

I have recently developed a Yeoman generator and am now looking to incorporate prompts for certain global configurations. My goal is to have the generator prompt users for their GitHub username and token during the initial run, and then somehow store this ...

Utilize jQuery ajax to pull in data from an external website

I've been doing some research on using jQuery ajax to extract links from an external website, but I'm a bit lost on where to begin. I'm taking on this challenge just to push my skills and see what I can accomplish. While reading about the S ...

Configuring a devServer proxy leads to a 404 error

Within my src/vue.config.js file, I have the following configuration: module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8081', changeOrigin: true, }, }, }, }; When I c ...

"Uncovering a memory leakage issue within a recursive polling function in JavaScript

Current issue in need of resolution: My team and I are currently working on a large application that was initially released around two years ago. We are in the process of adding a new "always-on" status screen to the application, which will be the default ...