What is the best way to make a JavaScript button change its class on the second click, either on itself or on other buttons with the same class?

I am trying my best, with my limited knowledge of Javascript, to write plain Javascript for some buttons to achieve the following:

a) Click any button, like button1, and its content will be shown b) Click the same button again, and its content will be hidden c) Click a button (e.g. button1), then click another button (e.g. button2), and display button2's content while hiding the previously clicked button's content (button1).

However, I can only manage two out of these three steps:

For instance, let's say we have three buttons:

Scenario 1

In Scenario 1, I can achieve a) but not b) or c)

I can click button1 to show its content, then click button2 to open its content and hide the content of button1. However, I cannot click button2 again to hide its content, so all button contents remain hidden.

The code snippet is as follows:

Scenario 2

In Scenario 2, I can achieve a) and b) but not c)

In this code snippet, I can make each button show and hide its content when clicked once to reveal and clicked again to hide. Unfortunately, when clicking on another button while the first one is still open, the first one does not hide:

Ideal Scenario 3:

As stated at the start, what I aim to accomplish is a combination of Scenarios 1 and 2:

a) Click any button, like button1, and its content will be displayed b) Click the same button again, and its content will be hidden c) Click a button (e.g. button1), then click another button (e.g. button2), and display button2's content while also closing the previously opened button's content (button1).

I've attempted tweaking my JS code like below, but I seem to be getting conflicting results - perhaps 'clicked' is always true? Or maybe my use of != is incorrect (or both).

let Buttons = document.querySelectorAll(".button");
for (let button of Buttons) {
    button.addEventListener('click', (e) => {
        const x = e.target;
        const y = document.querySelector(".clicked"); 
        const z = (y != x); 
        const q = (x = y);
        if (z) {
            z.classList.remove("clicked");
        }
        if (q) {
            q.classList.toggle("clicked"); 
        }
        x.classList.toggle("clicked");
    })
}

Any assistance would be greatly appreciated, but please refrain from using jQuery. Thank you.

Answer №1

If you want to achieve a similar functionality, you could try the following approach:

const buttons = Array.from(document.querySelectorAll(".button"));
buttons.forEach((button) => {
  button.addEventListener('click', () => {
    // Set all other buttons to not clicked and hide their content
    buttons.filter(b => b != button).forEach(b => {
      b.classList.remove('clicked');
      b.classList.add('not-clicked');
      b.nextElementSibling.classList.add('hidden')
    });
    // Toggle the visibility of the current button's content
    button.nextElementSibling.classList.toggle('hidden');
    if (button.nextElementSibling.classList.contains('hidden')) {
      button.classList.remove('clicked');
      button.classList.add('not-clicked');
    } else {
      button.classList.add('clicked');
      button.classList.remove('not-clicked');
    }
  });
});
.hidden {
  display: none;
}
.clicked {
  color: red;
}
<div>
  <button class="button not-clicked" type="button">Button 1</button>
  <p class="level-1 hidden" data-number="2">Content of button 1</p>
</div>
<div>
  <button class="button not-clicked" type="button">Button 2</button>
  <p class="level-1 hidden">Content of button 2</p>
</div>
<div>
  <button class="button not-clicked" type="button">Button 3</button>
  <p class="level-1 hidden">Content of button 3</p>
</div>

This code functions by setting all other buttons to 'not-clicked' and hiding their content when a specific button is clicked. It then toggles the visibility of the clicked button's content.

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

Add and alter a script tag within the Vue template

I am currently working on integrating a payment service into my platform. The payment service has provided me with a form that includes a script tag. This question is a follow-up to a previous query on inserting a script tag inside a Vue template. Here i ...

The array string is not being identified as a valid array

I'm currently experimenting with jQueryUI's AutoComplete feature to develop a search bar that allows users to input names and instantly locate the desired content. The response from my server backend looks like this: $.get("http://localhost/aca ...

Main menu items failing to display sub menu options

I am in need of assistance as I am facing the same issue on two WordPress twin websites that are using the same theme (Newmagz), which is no longer purchased and therefore not supported. The submenus in the main menu are simply not appearing. I have checke ...

Utilizing jQuery to execute a consistent action for every element on a webpage

After reading numerous related questions, I have come to the conclusion that none of them seem to address my specific situation. I am looking to add a border around a single element without affecting its parent elements. My attempt with the code below usi ...

Discover the method for populating Select2 dropdown with AJAX-loaded results

I have a basic select2 box that displays a dropdown menu. Now, I am looking for the most effective method to refresh the dropdown menu every time the select menu is opened by using the results of an AJAX call. The ajax call will yield: <option value=1 ...

"Comparing the similarity and accessibility of using the same browser session with a Firefox or Chrome

I'm working on a solution to close and open the same session in my browser using a Firefox extension. The code I have currently closes the browser and then opens the last session, but it also opens another window which is not desired. I want to be abl ...

Implement CSS to layer HTML 5 canvases while including a margin

I have a design conundrum in my app where I am using multiple stacked HTML canvas elements for drawing. My goal is to make the canvases fit perfectly within their containing div while also maintaining a left and bottom margin. This is how my HTML structur ...

Prisma unexpectedly updates the main SQL Server database instead of the specified database in the connection string

I have recently transitioned from using SQLite to SQL Server in the t3 stack with Prisma. Despite having my models defined and setting up the database connection string, I am encountering an issue when trying to run migrations. Upon running the commands: ...

Error encountered when sending information to web service repeatedly

After populating an array with data, the information is logged into a database using a web service when the array reaches a specific record count. However, upon calling the web service, I encountered an error related to a parameter being passed: Error Ty ...

Pictures on aspx websites utilizing a Master Page

On my master page, I have two images - a logo at the top and a Facebook link at the bottom. There is also an admin folder containing .aspx pages specifically for admin logins. For all non-admin pages, the images are accessed using the src of image/logo.jp ...

Guide on utilizing mongoose for handling multiple increment operations

Currently, I am developing a program that tracks different "accepts" and "denies". In this project, I am utilizing the findOneAndUpdate function from mongoose. However, I am encountering some issues with achieving the desired functionality. The data I am w ...

An error was caught: the object is not iterable and cannot read the property Symbol(Symbol.iterator) within the XMLHttpRequest function

const container = document.querySelector("#box"); request.open("GET","https://api.data.com/population/us"); request.send(); // To retrieve the response request.addEventListener("load",function(){ // console.log(this.responseText); const [da ...

Event delegation will be ineffective when the target element is nested within another element

After receiving a recommendation from my colleagues on Stackoverflow (mplungjan, Michel), I implemented the event delegation pattern for a comment list. It has been working well and I am quite excited about this approach. However, I have encountered an iss ...

Shifting listbox items + Postback or callback argument is not valid

My listbox contains 2 buttons to move items up and down. When shifting the position of pre-bound items, everything functions as expected. However, if I try to add a new item from a textbox, shift its position, and then save the form, an error arises. The e ...

What is the best way to retrieve data and handle error messages using the fetch API in Node.js?

I am attempting to utilize Node's 18 fetch API to send requests to a REST server. Below is the code snippet: const get = () => { let response = await fetch("10.0.0.12/test", { method: "GET", }); console.log(&quo ...

Implement authentication verification on all child endpoints within an express router

I have an express router set up and I want only authorized users to access its routes. I am currently using passport middleware. Instead of adding a check for req.user in every endpoint, is there a more efficient way to handle this? router.get("/", asyn ...

increase the selected date in an Angular datepicker by 10 days

I have a datepicker value in the following format: `Fri Mar 01 2021 00:00:00 GMT+0530 (India Standard Time)` My goal is to add 60 days to this date. After performing the addition, the updated value appears as: `Fri Apr 29 2021 00:00:00 GMT+0530 (India St ...

How to Extract the onClick Event Value from a Table Data (td) Element in C

I'm working on an HTML table with the following code: <table class="window" style="margin-top: 15px; text-align: center;"> <tr id="NavMonth"> <td id="m1" onclick=""> Jan </td> ...

What is the best way to stack col-xs-6 elements instead of having them side by side?

My form fields are currently set up using 3 col-xs-6 classes, but I'm not seeing the desired layout. I am aiming for: | col-xs-6 | | col-xs-6 | | col-xs-6 | However, what I am getting is: | col-xs-6 | col-xs-6 | | col-xs-6 | I understand that th ...

Problem with div selection and dynamic content in Rails 5

Currently, I am working on developing an application using Rails 5 and Ruby 2.4.0 with Bootstrap 4 Alpha 6 integration. The issue I am facing involves a dynamic select box that loads information about the selected item into a div below it. However, each t ...