Firing off an event when clicking a specific button from within a forEach() loop

Viewed 174

I am currently trying to set two different events on two different buttons, however, these buttons (h1's) are within a forEach() loop. Long story short, it goes like this: When clicking a button, the text will appear underneath it and disappear if clicked again (this is working perfectly so far). Now, I decided to add an svg with an animation, but for this I need to target the specific button since I need to apply different CSS depending on which button is clicked.

I can't seem to figure out how to set an event for one button since I've created a forEach() loop that calls the button and respective text from within the HTML template.

Is there anyone who can, from looking at these short code snippets, help me find a way to incorporate what I'm missing regarding the on click svg/animation?

NB: The JS code snippet below is currently firing off the animation that I would like to set for button 1 <h1 class="tourTitle> on both buttons.

<section id="tours">
    <h1 class="whatWeOffer">What we offer</h1>

    <template class="tourTemplate">
        <div id="singleTourArea">
            <h1 class="tourTitle"></h1>
            <p class="tourText"></p>
        </div>
    </template>
    <div id="tourArea"></div>
        <svg id="boatSvg" class="show" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2110 1350">
            <path d="M907.8.2c-31.9 80.3-71.4 157.6-117.9 230.4-29 45.5-61.7 91.7-67.7 145.3-11.9 106 83.4 200.2 78.1 306.7-12 18.7-42.3 11.3-57.6-4.8-15.3-16.1-24.1-38.3-42.1-51.3 22.5 14.2 53.5-8.1 58.2-34.2s-7.8-51.9-19.9-75.6c65.1 70.8 102 166.7 101.3 262.8-93.4-57-165.9-147.4-201.2-251 30.8 89.3 88.2 169.3 162.9 227 63 48.6 141.2 85.5 176.3 156.9 19.2 39.2 23.1 85.2 46.7 122 11.2 17.4 26.2 31.8 41.3 45.8 38.1 35.4 77.4 69.5 117.9 102.1 21.8 17.6 43.9 34.7 66 51.9 49.7 38.6 99.5 77.1 149.2 115.7" fill="none" stroke="#000" stroke-miterlimit="10"/>
        </svg>
</section>
function showTours(tours) {
    // 1. template clone
    const tourTemplate = document.querySelector(".tourTemplate").content;
    const tourArea = document.querySelector("#tourArea");
    
    tours.forEach((oneTour) => {
        const tourCopy = tourTemplate.cloneNode(true);

        tourCopy.querySelector(".tourTitle").textContent = oneTour.title.rendered;
        const tourText = tourCopy.querySelector(".tourText");
        tourText.textContent = oneTour.description;
        //Expand single tour
        tourCopy.querySelector(".tourTitle").addEventListener("click", function(){
            if (tourText.style.display === "block") {
                tourText.style.display = "none";

                document.querySelector("#boatSvg").classList.add("show");
                document.querySelector("#singleTripArea:nth-of-type(5n)").classList.remove("flashAnimation"); 
                document.querySelector("#singleTripArea:nth-of-type(3n)").classList.remove("flashAnimation"); 
                } else {
                tourText.style.display = "block";

                document.querySelector("#boatSvg").classList.remove("show");
                document.querySelector("#boatSvg").classList.add("boatAnimation"); 
                document.querySelector("#singleTripArea:nth-of-type(5n)").classList.add("flashAnimation"); 
                document.querySelector("#singleTripArea:nth-of-type(3n)").classList.add("flashAnimation"); 
                }
        })
        tourArea.appendChild(tourCopy);
    })
}
2 Answers

In your

tours.forEach((oneTour) => {
    //A bunch of stuff
});

You are looping tours and on each iteration, you can refer the current element as oneTour.

So, if oneTour is having a tourTitle class, then, instead of

tourCopy.querySelector(".tourTitle").addEventListener("click", function(){
    //A bunch of stuff    
});

you can do this:

oneTour.addEventListener("click", function(){
    //A bunch of stuff    
});

Note that it's possible that I did not quite get what you want to happen with what. If that's the case, I would welcome some further clarification of the problem.

If I understand correctly, you want to add different events to different elements, and attach them inside a forEach loop. Maybe try something like this (basic example):

function event1 () {
  console.log('This is the first button');
}

function event2 () {
  console.log('This is the second button');
}

var events = [event1, event2];

tours.forEach((oneTour, i) => {
  // Do some stuff
  someElement.addEventListener('click', events[i]);
}

I'm essentially just defining the event handlers outside the loop, storing them in a list, and getting the index of the forEach alongside the value. I then use the index to access the correct function. I hope that is of some help. (Or perhaps I did not quite understand).

Related