Ben
Ben

Reputation: 53

How to add event listeners to multiple elements with the same class and then only change CSS for specific other element

I basically want to make it possible to show and hide multiple blocks of text, completely separate to one another. So that when one of the buttons is pressed, the corresponding quote directly below it becomes visible (display: block), but only that quote.

This is what I have so far, but I have now ran in to a wall:

JS:

<script> 
    let btn = document.querySelectorAll('btn');
    let quote = document.querySelectorAll('quote');
    btn.addEventListener("click", function(){
        if (quote.style.display == "block") {
            quote.style.display = "none";
        } else {
            quote.style.display = "block";
        }
    });
</script>

HTML:

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

Upvotes: 4

Views: 3206

Answers (3)

biberman
biberman

Reputation: 5767

You have to declare an event listener for every button in a loop and declare the quote inside the listener. I also reversed the displayproperty values.

You also forgot a dot in the btn variable:
let btn = document.querySelectorAll('.btn')

let btn = document.querySelectorAll('.btn');
for (i = 0; i < btn.length; i++) {
    btn[i].addEventListener('click', function () {
        let quote = this.nextElementSibling;
        console.log('quote: ', quote);
        if (quote.style.display == "none") {
            quote.style.display = "block";
        } else {
            quote.style.display = "none";
        }
    });
}
<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

Upvotes: 2

Ramon de Vries
Ramon de Vries

Reputation: 1342

Using jQuery i made this:

With $(this) the button you clicked on, and .next() giving the next element.

you can find the next element (i added a check to make sure the next element has the class quote before running) and apply your styling

$('.btn').on('click', function() {
  if ($(this).next().hasClass('quote')) {
    $(this).next().css('display', 'block');
  }
});
p {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

<button class="btn">Click here to see the quote</button>
<p class="quote">blah blah blah</p>

Upvotes: 0

Arya
Arya

Reputation: 124

First of all, if you want to select class, it should be querSelectorAll('.btn') and querSelectorAll('.quote') (begin with a .).

Secondly, with querSelectorAll, your btn and quote variable will be lists of nodes (you should name it btns and quotes btw) so you won't be able to add event listener to it. What you should do is iterate throw your list and add event listener for each item:

let btns = [...document.querySelectorAll('.btn');
btns.map(btn => btn.addEventListener('click', (btn, idx) => handleBtnClick(btn, idx));

Then in handleBtnClick, you should select the div with corresponding idx and make it visible, while the others div invisible:

const handleBtnClick = (btn, idx) => {
    let quotes = [...document.querySelectorAll('.quote')];
    quotes.map( (quote, quotedIdx) => {
       if (quoteIdx === idx) {
          quote.style.display = 'block';
       } else {
          quote.style.display = 'none';
       }
    }
    

This code is no optimizied, please refacto as you please

Upvotes: 0

Related Questions