# JavaScript Event Listeners

### Working with event listeners

For the past week I've been working on my final school project and something that had been a bit of a challenge for me ended up being event listeners. Over the course of a few assignments that I had been doing, I simply did not understand why mine never worked as intended and as I was doing my final project I finally got the cause of my problem with them and I'll try as much to explain (I'm still a beginner there may be a few problems or mistakes so please bear with me) how I got to get over the issues I was facing.

### Correct positioning of event listeners

In my final project, we needed to work with API's for our websites and I chose the NASA Astronomical Picture of the Day API which basically shows a really captivating astronomical picture every day.

![My project assignment](https://cdn.hashnode.com/res/hashnode/image/upload/v1713007843318/0b3f5098-161f-4b56-a3cd-af3922bc63ec.png align="center")

I managed to create a simple web page which showed a particular picture with it's description and it had some functionalities such as searching a particular date, moving to the next or previous date and a history section which recorded the dates you visited. I wanted the history section to be such that you could click on a particular date and the picture with the explanation would show up. I created an array for the date history and ensured visiting a particular date twice wouldn't record it twice.

```javascript
//my initial attempt
const dateHistoryArray = []

function renderData(data) {
 // Code for rendering data...

// Extract the new date from the fetched data
let newDate = data.date;
// Check if the new date is not already in the history array
  if (dateHistoryArray.indexOf(newDate) === -1) {
// If it's a new date, add it to the history array
    dateHistoryArray.push(newDate);
// Create a new container element to hold the date and delete button
    const container = document.createElement("div");
    container.innerHTML = `<span style="display:inline-block"><li class="listItem">${newDate}</li></span> <span style = "display:inline-block"><button class = "listDelButton">x</button></span>`;
    dateHistoryList.appendChild(container);
}
//attempt to try and render the dates
const dateHistoryList = document.querySelectorAll(".listItem")
dateHistoryList.forEach((item) => {
    item.addEventListener("click", ...
}
```

Initially, my intention was to immediately attach event listeners to the dynamically rendered dates to handle user interaction, such as clicking on a date to display its corresponding image.

However, the asynchronous nature of fetching data meant that the `querySelectorAll` method initially returned an empty list, as the dates had not yet been appended to the DOM meaning the event listeners wouldn't work anyway.

I then had the idea to simply encapsulate the event listener within a function then call it each time a new date has been appended. While it initially appeared to work, I encountered a problem. Clicking on a date would sometimes display the wrong image or cycle through multiple images. At the time I simply couldn't understand why that was happening.

```javascript
function renderData(data) {
 // Code for rendering data...

// Extract the new date from the fetched data
let newDate = data.date;
// Check if the new date is not already in the history array
  if (dateHistoryArray.indexOf(newDate) === -1) {
// If it's a new date, add it to the history array
    dateHistoryArray.push(newDate);
// Create a new container element to hold the date and delete button
    const container = document.createElement("div");
    container.innerHTML = `<span style="display:inline-block"><li class="listItem">${newDate}</li></span> <span style = "display:inline-block"><button class = "listDelButton">x</button></span>`;
    dateHistoryList.appendChild(container);
    const dateElement = container.querySelectorAll(".listItem")
    eventListenerFunction(dataElement)
}
function eventListenerFunction(dataElement) {
    dataElement.forEach((date) => {
        dataElement.addEventListener("click", ...)
    }
}
```

### Issues with multiple event listeners

I did some research and realized i had been doing it all wrong all this time. After some research, I discovered the root cause: multiple event listeners were being added to previously recorded dates with each new addition. This resulted in chaotic behavior and inconsistent rendering of images.

It took a while to find the solution. To attach the event listener immediately after adding a new date, preventing the accumulation of redundant listeners, then do we pass on the function that actually renders the date. Though seemingly straightforward, this realization marked a significant breakthrough in my understanding of event handling in JavaScript.

```javascript

  let newDate = data.date;
  if (dateHistoryArray.indexOf(newDate) === -1) {
    dateHistoryArray.push(newDate);
    const container = document.createElement("div");
    container.innerHTML = `<span style="display:inline-block"><li class="listItem">${newDate}</li></span> <span style = "display:inline-block"><button class = "listDelButton">x</button></span>`;
    dateHistoryList.appendChild(container);
    let listItem = container.querySelector(".listItem");
    listItem.addEventListener("click", renderListItem);
    const delButton = container.querySelector(".listDelButton");
    delButton.addEventListener("click", removeDate);
```

This is still an earlier project with many to come. It's good knowing there's still a lot more to learn and that I can actually overcome the blocks I face. It's not the end of the road. I'll keep trying till I make it.
