Javascript click on button to change backgroud color

Viewed 118

I want to click one by one within these buttons and change the background colour of them to red. If I select all A, B and C, then every button should change to red. When I clicked one by one to every button, they change colour back to default color.

<button type="button">All</button>
<button type="button">A</button>
<button type="button">B</button>
<button type="button">C</button>

Here is my code

optAll.addEventListener('click', function (e) {
    e.target.style.backgroundColor = "red";
    optA.style.backgroundColor = "red";
    optB.style.backgroundColor = "red";
    optC.style.backgroundColor = "red";
    optD.style.backgroundColor = "red";
});
6 Answers

You need to begin by splitting up the code where you assign the click handlers.

To avoid unnecessary queries, you can query once and then use the results later multiple times.

const main = document.querySelector('#all');
const ones = document.querySelectorAll('.one');

Then assign the handler to the button that toggles them all. It will toggle them by iterating over the elements you got further up.

I am assuming you also want to toggle the "main" button, if not, remove that line.

main.addEventListener('click', function (e) {
    e.target.style.backgroundColor = "red";
    ones.forEach( el => {
      el.style.backgroundColor = "red";
    });
});

Then the "toggle one" buttons, iterate over them and assign a handler that only affects the element clicked.

ones.forEach( el => {
  el.addEventListener('click', function (e) {
    e.target.style.backgroundColor = "red";
  });
});

const main = document.querySelector('#all');
const ones = document.querySelectorAll('.one');
const updatedColor = 'red';
const originalColor = main.style.backgroundColor;

main.addEventListener('click', function (e) {
    updateColor(e.target);
    ones.forEach( el => {
      updateColor(el);
    });
});

ones.forEach( el => {
  el.addEventListener('click', function (e) {
    updateColor(el);
  });
});

// Update the element color based on the current color
function updateColor(el) {
  if (el.style.backgroundColor === originalColor) {
    el.style.backgroundColor = updatedColor;
  } else {
    el.style.backgroundColor = originalColor;
  }
}
<button id="all" type="button">All</button>
<button class="one" type="button">A</button>
<button class="one" type="button">B</button>
<button class="one" type="button">C</button>

UPDATE: to handle going back to the original color on second, or any even number, clicks, we can first store the original color in a constant.

const originalColor = main.style.backgroundColor;

And then use that constant, to update the button background color conditionally, better to do it in a separate function, to avoid repetition.

function updateColor(el) {
  if (el.style.backgroundColor === originalColor) {
    el.style.backgroundColor = updatedColor;
  } else {
    el.style.backgroundColor = originalColor;
  }
}

For this, you will need more than just one event. Each button should have a separate click event with a toggle for 'red' and 'default'.

optA.addEventListener('click', function (e) {
  e.target.style.backgroundColor == 'red'?
    e.target.style.backgroundColor = 'default':
    e.target.style.backgroundColor = 'red';
});

optB.addEventListener('click', function (e) {
  e.target.style.backgroundColor == 'red'?
    e.target.style.backgroundColor = 'default':
    e.target.style.backgroundColor = 'red';
});

optC.addEventListener('click', function (e) {
  e.target.style.backgroundColor == 'red'?
    e.target.style.backgroundColor = 'default':
    e.target.style.backgroundColor = 'red';
});

I recommend creating a function to toggle the background instead of just ctrl+c and ctrl+v as I just did

And For the "All" button you will need an event that checks the background of all the other buttons.

optAll.addEventListener('click', function (e) {
  (optA.style.backgroundColor == "red" && 
   optB.style.backgroundColor == "red" && 
   optC.style.backgroundColor == "red")?
     e.target.style.backgroundColor = 'red':
     e.target.style.backgroundColor = 'default';
});

I believe something like this should work.

let btn_all = document.getElementById("btn_all");
let btn_A = document.getElementById("btn_A");
let btn_B = document.getElementById("btn_B");
let btn_C = document.getElementById("btn_C");

let allButtons = [btn_all,btn_A,btn_B,btn_C];

function changeColor (e) {
    let currentColor = e.target.style.backgroundColor;
    if (currentColor != "red") {
        e.target.style.backgroundColor = "red";
    }
    else {
        e.target.style.backgroundColor = "";
    }
    
}
function changeColorAll (e) {
    let currentColor = e.target.style.backgroundColor;

    if (currentColor != "red") {
        allButtons.forEach( function(element, index) {
            element.style.backgroundColor = 'red';
        });
    }
    else {
        allButtons.forEach( function(element, index) {
            element.style.backgroundColor = '';
        });
    }
}

btn_all.addEventListener("click", changeColorAll);
btn_A.addEventListener("click", changeColor);
btn_B.addEventListener("click", changeColor);
btn_C.addEventListener("click", changeColor);
<button type="button" id="btn_all">All</button>
<button type="button" id="btn_A">A</button>
<button type="button" id="btn_B">B</button>
<button type="button" id="btn_C">C</button>
https://stackoverflow.com/questions/65630594/javascript-click-on-button-to-change-backgroud-color#

Try this code you only have to add two callbacks one for all the other buttons and one for the "all" button. And inside the "all" button callback you have to deal with a list that contains a reference to all your button objects

Here is the solution you need. This solution involves the for cycle. To select All buttons, you define the first button as optAll[0]:

optAll[0].onclick = function() {}

To select each button - A, B and C, except for All in the for cycle, the numbering starts from 1, not from 0:

for (var i = 1; i < optAll.length; i++) {}

And you declare the button only once:

let opt = document.querySelectorAll('button');

let opt = document.querySelectorAll('button');

opt[0].onclick = function() {
  for (var i = 0; i < opt.length; i++) {
    opt[i].style.backgroundColor = "red";
  }
}

for (var i = 1; i < opt.length; i++) {
  opt[i].onclick = function(event) {
    this.style.backgroundColor = "red";
  }
}
<button type="button">All</button>
<button type="button">A</button>
<button type="button">B</button>
<button type="button">C</button>

You could wrap the buttons inside of a <div> with a class i.e. button-set. This way you can access e.target.target.parentElement to get the wrapping div when clicking on a button.

If you activate the "All" option, it will deselect all active buttons. If you activate any other button, it will not deactivate any other button, unless the "All" button is already active.

In the example below, the button.dataset.active is used to set the data-active attribute for a given button. This attribute gets removed upon deactivation. The attribute is also used as a CSS rule to visually change the appearance of the button when active.

const ButtonSet = selector => {
  const _buttonSet = document.querySelector(selector);
  const handleClick = e => {
    const button = e.target,
      group = button.parentElement,
      allButton = [...group.querySelectorAll('button')]
        .find(button => button.textContent === 'All'),
      allActive = allButton.dataset.active === 'true',
      isActive = button.dataset.active === 'true';
    if (isActive) { delete button.dataset.active; }
    else { button.dataset.active = true; }
    if (button === allButton) {
      group.querySelectorAll('button').forEach(child => {
        if (child !== button) { delete child.dataset.active; }
      });
    } else {
      if (allActive) { delete allButton.dataset.active; }
    }
  };
  _buttonSet.querySelectorAll('button')
    .forEach(button => button.addEventListener('click', handleClick));
  return _buttonSet;
}

const getButtonSetValue = ref => [...ref.querySelectorAll('button')]
  .filter(button => button.dataset.active === 'true')
  .map(button => button.textContent);

ButtonSet('.button-set').addEventListener('click', e => {
  const value = getButtonSetValue(e.currentTarget);
  document.querySelector('#result > span').textContent = value.join(', ');
});
.as-console-wrapper { max-height: 4em !important; }

:root {
  --button-set-active-color: #AAF;
  --button-set-active-hover-color: #CCF;
  --button-set-button-color: #EEE;
  --button-set-button-hover-color: #FFF;
}

.button-set {
  display: flex;
  flex-direction: row;
  border: thin solid grey;
  height: 1.5em;
}

.button-set button {
  width: 25%;
  border: none;
  border-right: thin solid grey;
  cursor: pointer;
  background: var(--button-set-button-color);
}

.button-set button:hover {
  background: var(--button-set-button-hover-color);
}

.button-set button:last-child {
  border-right: none;
}

.button-set button:focus {
  outline: 0;
}

.button-set button[data-active="true"] {
  background: var(--button-set-active-color);
}

.button-set button[data-active="true"]:hover {
  background: var(--button-set-active-hover-color);
}

#result {
  margin-top: 0.5em;
}

#result label {
  font-weight: bold;
}
<div class="button-set">
  <button>All</button>
  <button>A</button>
  <button>B</button>
  <button>C</button>
</div>

<div id="result">
  <label>Selected:</label>
  <span></span>
</div>

I would create the class button-red in order be able to toggle the class back and forth between the original color and the red color.

Then I would add a listener to each button and also create a variable optAll where all buttons can be stored so that we can loop through it to change the color of the buttons when the ALL button is clicked. Then add a function changeColor(btn) to change the color of the button in question and make things cleaner overall, and call it in each listener.

const optAll= document.querySelectorAll('.buttons');
const optA=document.getElementById("optA");
const optB=document.getElementById("optB");
const optC=document.getElementById("optC");

function changeColor(btn){
btn.classList.toggle("button-red");
}

optAll[0].addEventListener('click', function (e) {
   optAll.forEach( btn => {
   changeColor(btn);
    });       
});

optA.addEventListener('click', function (e) { 
 changeColor(e.target);
});
optB.addEventListener('click', function (e) { 
 changeColor(e.target);
});
optC.addEventListener('click', function (e) { 
 changeColor(e.target);
});
.button-red {
    background-color:red
}
<button id="optAll" class="buttons" type="button">All</button>
<button id="optA" class="buttons" type="button">A</button>
<button id="optB" class="buttons" type="button">B</button>
<button id="optC" class="buttons" type="button">C</button>

Related