Event delegation not working on dynamic buttons

176 Views Asked by At

No matter what I try, the .onclick or addEventListener 'click' will not work on my dynamically created buttons and I can't figure out why. As I was looking for solutions, I came across Event Delegation and I looked through 3 different websites and looked at the examples. I was sure this was going to solve my problem and I tried to mimic the examples but still it isn't working. I posted a question on here earlier but it was immediately removed because apparently it was too similar to another question (that was 12 years old!) but when I looked at that question they were using jQuery. I'm still a beginner in JS so I would prefer to understand how to resolve this in plain JS and I'm hoping this won't be removed.

This is my code:

document.addEventListener('DOMContentLoaded', function() {
userData();
document.querySelector('.list-group').addEventListener('click', function(e) {
    if(e.target && e.target.nodeName == "BUTTON"){
        console.log(e.target.id);
    }
});

})

function userData() {
    fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json())
    .then(users => {
        const h6 = document.createElement("h6");
        h6.innerText = "List of Users";
        const userList = document.createElement("div");
        userList.className = "list-group";
        users.forEach(function(user) {
            const userButton = document.createElement("button");
            userButton.className = "list-group-item list-group-item-action";
            userButton.id = `${user.id}`;
            userButton.innerHTML = `
            <strong>${user.name}</strong><br>
            ${user.email}<br>
            ${user.address.city}<br>
            `;
            userList.appendChild(userButton);
        });
        const container = document.querySelector('#response');
        container.appendChild(h6);
        container.insertBefore(userList, h6.nextSibling);
    });
}

function userSelect(user_id) {
    fetch(`https://jsonplaceholder.typicode.com/users/${user_id}`)
    .then(response => response.json())
    .then(user => {
        console.log(user);
    });
}

What I have now is a list of users and ultimately I want to be able to click on a user and bring up the full details of that user. At first I was trying to use the onclick function to redirect to the userSelect function but when that failed I looked around and found Event Delegation and still no luck. I tried to move the document.querySelector('.list-group) section down at the end of the userData function and still no luck. When I click on a button nothing shows up in console, if I use the userSelect function directly in console a user object appears. I'm at a real loss on how to get this to work. Please help!

1

There are 1 best solutions below

0
On

Since function userData is making asynchronous call, the issue seems to be that you are adding the click event handler before the element with class '.list-group' got created. You should use something like this to add click handler

 document.addEventListener('DOMContentLoaded', function () {
        userData().then(response => {
            document.querySelector('.list-group').addEventListener('click', function (e) {
                if (e.target && e.target.nodeName == "BUTTON") {
                    console.log(e.target.id);
                }
            })
        });
    })

Try below snippet:

document.addEventListener('DOMContentLoaded', function() {
  userData().then(response => {
    document.querySelector('.list-group').addEventListener('click', function(e) {
      if (e.target && e.target.nodeName == "BUTTON") {
        console.log(e.target.id);
      }
    })
  });
})

function userData() {
  return fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json())
    .then(users => {
      const h6 = document.createElement("h6");
      h6.innerText = "List of Users";
      const userList = document.createElement("div");
      userList.className = "list-group";
      users.forEach(function(user) {
        const userButton = document.createElement("button");
        userButton.className = "list-group-item list-group-item-action";
        userButton.id = `${user.id}`;
        userButton.innerHTML = `
            <strong>${user.name}</strong><br>
            ${user.email}<br>
            ${user.address.city}<br>
            `;
        userList.appendChild(userButton);
      });
      const container = document.querySelector('#response');
      container.appendChild(h6);
      container.insertBefore(userList, h6.nextSibling);
    });
}
<div id="response">
</div>

or you can move the addEventListener code to end of userData