2

I'm trying to implement the following functionality without jQuery:

$(document).on('click', 'a.no-target', function(e) {
    e.preventDefault();
});

I have tried with the following piece of code:

document.addEventListener('click', function(e) {
    if (e.target.tagName == 'A' && e.target.className.indexOf('no-target') > -1) {
        e.preventDefault();
    }
});

My problem here is that if I have nested elements like the following ones:

<a href="#" class="more no-target">
    <span class="more">Nested element</span>
</a>

the event's target is the <span> instead of the <a>.

Is there a generic solution for this case without having to check the target's parent?

Note: I need this eventListener to work with dynamically created elements, so I can't attach it directly to the a.no-target elements.

Thanks.

LostMyGlasses
  • 3,074
  • 20
  • 28

2 Answers2

6

This is traversing upwards until you find the element of the listener.

document.addEventListener('click', function(e) {
    var elem = e.target;
    while (elem != document) {
       if (elem.tagName == 'A' && elem.className.match(/\bno\-target\b/) !== null) {
        e.preventDefault();
       }
       elem = elem.parentNode;
    }
});
MinusFour
  • 13,913
  • 3
  • 30
  • 39
  • I like this answer but only have a remark on the class detection: an element with any class containing "no-target" string would match. I would refer to [answer to this question](http://stackoverflow.com/questions/5085567/hasclass-with-javascript-or-site-with-jquery-to-javascript-translation) on how to implement the jQuery `hasClass()` in POJS. – Laurent S. Aug 31 '15 at 14:18
  • @Nico I thought the question was about **not traversing**, or did you only mean not checking the first parent? – Amit Aug 31 '15 at 14:21
  • @LaurentS. Thanks, I've put down the alternative. – MinusFour Aug 31 '15 at 14:23
  • @Amit in fact you're right, but this solution looks more elegant than I expected when thinking about the traversal, so it's fine for me. – LostMyGlasses Aug 31 '15 at 14:27
0

Is there a generic solution for this case without having to check the target's parent?

No, there isn't. The reason could be illustrated with the following example:

<span id="target">
  <span class="a">
    <span class="b">
      <span class="c">Click me!</span>
    </span>
  </span>
</span>

If you were to attach the handler to "target", and move your mouse over the text, you won't see a hand cursor, but you could click it and an event will fire. It will also bubble (or be captured and dispatched, depending how you attached...) along the tree till it reaches the "target" element, where your event handler will be executed. The key point here is that there is nothing special about the <a> element in your question. You could've just as well wanted to look for span.b which is the direct parent, or span.a which is just along the path. You can't find that out without traversing the tree, which is fairly simple to do, like MinusFour's answer shows.

Amit
  • 45,440
  • 9
  • 78
  • 110