Tony
Tony

Reputation: 397

How to reset the background colour of all other buttons and highlight the selected button when clicked?

I am trying to reset all the background colours when I click on one button and change the colour of the selected button. I want in the beginning for one button to have the background colour of dark grey as shown in the snippet, and when I click on another button all of the buttons would be resetted back to white and the clicked button will turn dark grey. How can I achieve this?

Right now when I click on another button nothing happens.

This is my code, what is wrong?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>

        /* Style the buttons */
        .portfolio-buttons {
            border: none;
            outline: none;
            padding: 12px 16px;
            /* background-color: white; */
            cursor: pointer;
        }

        .portfolio-buttons-normal {
            background-color: white;
        }

        .portfolio-buttons:hover {
            background-color: #ddd;
        }

        .portfolio-buttons-active {
            background-color: #666;
            color: white;
        }
    </style>
</head>

<body>
    <div id="myBtnContainer">
        <button class="portfolio-buttons portfolio-buttons-normal portfolio-buttons-active">Show
            all</button>
        <button class="portfolio-buttons portfolio-buttons-normal" >.html</button>
        <button class="portfolio-buttons portfolio-buttons-normal">.css</button>
        <button class="portfolio-buttons portfolio-buttons-normal" >.js</button>
        <button class="portfolio-buttons portfolio-buttons-normal" >.java</button>
        <button class="portfolio-buttons portfolio-buttons-normal" >.py</button>
    </div>
    <script>

        
        function changeClass(button, classRef) {

            button.classList.forEach((className) => {

                if (className.startsWith("portfolio-buttons-active")) button.classList.remove(className);

            });

            console.log(classRef);
            button[classRef].classList.add("portfolio-buttons-active");
        }


        document.querySelectorAll("portfolio-buttons").forEach((button, buttonNum) => {
            button.addEventListener("click", function () {
                document.querySelectorAll(".portfolio-buttons-normal").forEach((item) => {
                    changeClass(item, buttonNum);
                    console.log(buttonNum);
                });
            });
        });
    </script>
</body>

</html>

Upvotes: 2

Views: 1710

Answers (3)

FluffyKitten
FluffyKitten

Reputation: 14312

You are over-complicating it :) You are setting up your click listener correctly, but you just need 2 simple steps inside the listener:

1. Reset the current active button: simply get all buttons with the active class (we don't care about the rest, so no need to process them!) and remove it:

document.querySelectorAll(".portfolio-buttons-active").forEach((button) => {
     button.classList.remove("portfolio-buttons-active");
});

2. Set the clicked button to active: your click handler is added to the button so we when that button is clicked button, add the active class to it:

    button.classList.add("portfolio-buttons-active");

That's it! Putting this together all you need is the following:

document.querySelectorAll(".portfolio-buttons").forEach((button) => {
  button.addEventListener("click", function() {

    // Reset the currently active buttons:
    document.querySelectorAll(".portfolio-buttons-active").forEach((button) => {
        button.classList.remove("portfolio-buttons-active");
    });

    // Add the active class to the clicked button
    button.classList.add("portfolio-buttons-active");
  });
});

Working Example: I've put steps 1 and 2 into functions in this code, in case you need to add more functionality in each step later

/* Add the active class to the button passed in */
function setThisButtonActive(button) {
  button.classList.add("portfolio-buttons-active");
}

/* select all active buttons, and remove the active class from them */
function resetActiveButton() {
  document.querySelectorAll(".portfolio-buttons-active").forEach((button) => {
    button.classList.remove("portfolio-buttons-active");
  });
}

document.querySelectorAll(".portfolio-buttons").forEach((button) => {
  button.addEventListener("click", function() {
    resetActiveButton();
    setThisButtonActive(button);
  });
});
/* Style the buttons */

.portfolio-buttons {
  border: none;
  outline: none;
  padding: 12px 16px;
  /* background-color: white; */
  cursor: pointer;
}

.portfolio-buttons-normal {
  background-color: white;
}

.portfolio-buttons:hover {
  background-color: #ddd;
}

.portfolio-buttons-active {
  background-color: #666;
  color: white;
}
<div id="myBtnContainer">
  <button class="portfolio-buttons portfolio-buttons-normal portfolio-buttons-active">Show
            all</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.html</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.css</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.js</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.java</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.py</button>
</div>

Upvotes: 2

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20944

You are missing a . in the querySelectorAll where you select the buttons. So it's looking for the element portfolio-buttons instead of the class.

The classList interface has a contains method which checks if a class is present on an element. So there is no need to loop and check the className string. Also there is no need at all, if the class is not on the element nothing is removed.

For the reset button, give it a way to identify it's uniqueness. In the example above I gave it a value attribute with a string in it. When clicking check the if it is the reset button that is clicked and simply don't add a new active class.

const buttons = document.querySelectorAll(".portfolio-buttons");
buttons.forEach((button) => {
  button.addEventListener('click', event => {
    buttons.forEach(button => button.classList.remove('portfolio-buttons-active'));
    if (button.value !== 'reset') {
      button.classList.add('portfolio-buttons-active');
    }
  });
});
/* Style the buttons */

.portfolio-buttons {
  border: none;
  outline: none;
  padding: 12px 16px;
  /* background-color: white; */
  cursor: pointer;
}

.portfolio-buttons-normal {
  background-color: white;
}

.portfolio-buttons:hover {
  background-color: #ddd;
}

.portfolio-buttons-active {
  background-color: #666;
  color: white;
}
<div id="myBtnContainer">
  <button class="portfolio-buttons portfolio-buttons-normal portfolio-buttons-active" value="reset">Show all</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.html</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.css</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.js</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.java</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.py</button>
</div>

Upvotes: 2

Dan Knights
Dan Knights

Reputation: 8368

You could simplify it by checking e.target:

const buttons = document.querySelectorAll(".portfolio-buttons");

buttons.forEach(button => {
  button.addEventListener("click", function(e) {
    e.target.classList.add('portfolio-buttons-active');
    
    buttons.forEach(item => {
      if (item !== e.target) {
        item.classList.remove('portfolio-buttons-active');
      }
    });
  });
});
.portfolio-buttons {
  border: none;
  outline: none;
  padding: 12px 16px;
  /* background-color: white; */
  cursor: pointer;
}

.portfolio-buttons-normal {
  background-color: white;
}

.portfolio-buttons:hover {
  background-color: #ddd;
}

.portfolio-buttons-active {
  background-color: #666;
  color: white;
}
<div id="myBtnContainer">
  <button class="portfolio-buttons portfolio-buttons-normal portfolio-buttons-active">Show
            all</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.html</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.css</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.js</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.java</button>
  <button class="portfolio-buttons portfolio-buttons-normal">.py</button>
</div>

If e.target isn't the current element in the loop, then remove the active class, otherwise, add the active class.

Upvotes: 1

Related Questions