1

Sorry for another duplicate.

I'm trying to bind a click event listener to links which will be dynamically created later. Unfortunately this doesn't work:

document.querySelector('body').addEventListener('click', function(e) {
    if (e.target.tagName.toLowerCase() === 'a') {
        e.preventDefault();
        console.log("click")
    }
});

Strangely it also doesn't work on a link which is not created dynamically. It is however working on the body, but that's not the target.

I also tried if (e.target.classList.contains("someclass")) {}

The DOM nodes are body->header->div->a if that makes a difference. (?)

Thanks for any advice on how to make it work!

5
  • 1
    I think the first question here is: is your event handler triggering? If you add console.log('foo') to the handler on the parent element, and click the (child) link, does it fire? If not, there's a problem with your understanding of event delegation (and we'll likely need to see your DOM/HTML more). If it is, there's a problem with your logic ... but the two are very different problems. Commented May 30, 2020 at 19:01
  • 1
    This current piece of code is working for static links jsbin.com/caqocogoci/edit?html,js,console,output What do you want to achieve can you share you html code as well that you are trying to work on? Commented May 30, 2020 at 19:03
  • 1
    @JérémieBardon nope Commented May 30, 2020 at 19:06
  • 2
    @JérémieBardon You should read up on how "event delegation" works (also referred to as "event bubbling"). It's very much a valid strategy to ensure your event handlers fire even on elements newly-added to the DOM. Commented May 30, 2020 at 19:22
  • Oh ok! Thank you very much doesn't know about that! So i supposed it's also better for performence since we don't have to create an event listener for each input? Commented May 31, 2020 at 22:56

1 Answer 1

1

When using target, sometimes the target is not the expected element.
See for example this code: the dynamically generated <a> have inner <span> Elements.
On click the target will be that span.

To get around that minor problem we can use the .closest() selector, in both cases, span or no span:

document.querySelector('body').addEventListener('click', function(e) {
    if (e.target.closest('a')) { // All oyu need
        e.preventDefault();
        console.log("click")
    }
});

setTimeout(() => {
  document.querySelector("#links").insertAdjacentHTML("beforeend", `
    <a href="#"><span>One</span></a>
    <a href="#"><span>Two</span></a>
  `);
}, 1000);
<header><div id="links"></div></header>

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

1 Comment

You're right! 😃 Thanks! It works now. There was indeed a span element inside the link element! I didn't know about the closest() selector, it'll come in handy later again. Thanks, stay healthy!

Your Answer

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