0

I'm trying to listen for a click event on a node list to add a CSS property, I don't want two nodes to have the property and I also want to toggle the CSS property on any of the node list with a second click, I can't seem to get the right guard clause to use, any Help.

enter code here

const action = document.querySelectorAll ('.item');

const clearColor = function() {
  action.forEach(function(item) {
    item.classList.remove('item-color');
  })
}

action.forEach(function(item) {
  item.addEventListener("click", function(e) {
    const target = e.target; 
    clearColor();
    target.classList.toggle("item-color")
  })
})
.hidden {
  display: none;
}

.item {
  margin: 10px;
}

.item-color {
  background-color: red;
}
<div class="action">
  <div class="item">pizza</div>
  <div class="item">rice</div>
  <div class="item">spaghetti</div>
  <div class="item">honey</div>
  <div class="item">cheese</div>
</div>

**strong text**
1
  • You call remove then toggle which will leave it on Commented Aug 2, 2022 at 12:13

3 Answers 3

2

You're almost there. There is a small problem here:

  1. The user clicks on an item.
  2. All items get their CSS class removed.
  3. The clicked item gets a CSS class added if it doesn't already exist.

The subtle thing here is that "if it doesn't already exists" is always true for the clicked item, because you just removed its CSS class in step 2.

The solution is to not remove the class in step 2:

const clearColor = function(except) {
  action.forEach(function(item) {
    if (item === except) {
      return;
    }
    item.classList.remove('item-color');
  })
}

// ...

clearColor(target);

By filtering out the clicked element from the items you're removing the CSS classes from, .toggle() will work as expected.

Sign up to request clarification or add additional context in comments.

Comments

1

This is the solution I came up with. Not the best but gets the job done.

const action = document.querySelectorAll ('.item');

const clearColor = function() {
  action.forEach(function(item) {
    item.classList.remove('item-color');
  })
}

action.forEach(function(item) {
  item.addEventListener("click", function(e) {
    const target = e.target; 
    if(target.classList.contains("item-color")){
        clearColor();
    }else{
        clearColor();
        target.classList.toggle("item-color")
    }
  })
})
.hidden {
  display: none;
}

.item {
  margin: 10px;
}

.item-color {
  background-color: red;
}
<div class="action">
  <div class="item">pizza</div>
  <div class="item">rice</div>
  <div class="item">spaghetti</div>
  <div class="item">honey</div>
  <div class="item">cheese</div>
</div>

Comments

0

Try something like this.

const action = document.querySelectorAll('.item');

action.forEach(function(item) {
  item.addEventListener('click', (e) => {
    item.classList.toggle('item-color');
    for(let i = 0; i < action.length; i++){
      if(e.currentTarget != action[i]){
        action[i].classList.remove('item-color');
      }
    }
  });
})
.hidden {
  display: none;
}

.item {
  margin: 10px;
}

.item-color {
  background-color: red;
}
  <div class="action">
      <div class="item">pizza</div>
      <div class="item">rice</div>
      <div class="item">spaghetti</div>
      <div class="item">honey</div>
      <div class="item">cheese</div>
  </div>

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.