3

How can I determine if a bubbling event was already handled before.

I want to handle a click event that was performed on a .card element. The event handler should trigger a click event on the first link in that card. If the user clicks on the second link in that card, the card's event handler should do nothing.

So I want to find a way, if any event handler (built-in or custom, including those that I have no control over) was called before.

Edit

This is not a question about a specific issue I have, but a general question on DOM event handling.

Edit 2

For popular demand (1 comment :) ) I'll add some example code.

This example will not fully work, as there are restrictions to links in SO snippets. I have a fully working example on Codepen

;
(function () {
  var selectors = []
  var subs = []

  function triggerMouseEvent(
    event,
    target,
    options
  ) {
    options = Object.assign({
      view: window,
      bubbles: true,
      cancelable: true
    }, options)
    const e = new MouseEvent(event, options)
    setTimeout(function () {
      target.dispatchEvent(e)
    }, 10)
  }

  function delegateClick(selector, subSelectors) {
    var selector = selectors.push(selector) - 1;
    var sub = subs.push(subSelectors) - 1;
    return {selector,sub}
  }

  function undelegateClick({selector, sub}) {
    selectors.splice(selector, 1);
    subs.splice(sub, 1);
  }
  
  
  function evnt(e) {
    selectors.forEach(function (selector, index) {
      if (e.target.closest(subs[index].join(','))) {return}
      var s = e.target.closest(selector)
      if (!s) {return}

      var selEl
      subs[index].find(function (sub) {
        return selEl = s.querySelector(sub)
      })
      if (selEl && e.target !== selEl) {
        triggerMouseEvent(e.type, selEl, {
          altKey: e.altKey,
          ctrlKey: e.ctrlKey,
          metaKey: e.metaKey
        })
      }
      
      
    })
  }
  document.addEventListener('click', evnt)
//   document.addEventListener('mouseover', evnt)

  window.delegateClick = delegateClick
  window.undelegateClick = undelegateClick
})();



dup = delegateClick('.card', ['a.act-on','button.act-on'])
.card {
  margin: 20px;
  border: 1px solid;
  padding: 20px;
}
.card:hover {
  background-color: gold;
  cursor: pointer;
}

body {
  display: flex;
}
<div class="card">
  <h1>Click this card</h1>
  <p>The action of the following button will be performed</p>
  <button class="act-on" onClick="alert('Button pressed!')">Button!</button>
</div>
<div class="card">
  <h1>Click this card</h1>
  <p>The action of the following link will be performed <p>
  <a class="act-on" href="https://example.org" target="_blank">example.org</a>
</div>
<div class="card">
  <h1>Click this card</h1>
  <p>The action of the following link will be performed</p>
  <p>The link is preferred to the button</p> 
  <button class="act-on" onClick="alert('Button pressed!')">Button!</button>
  <a class="act-on" href="https://example.org" target="_blank">example.org</a>
</div>
<div class="card" style="background-color: pink; border-color:red">
  <h1>Click this card</h1>
  <p><strong>If this button is pressed, the action of the link should not be done</strong></p>
  <button class="dont-act-on" onClick="alert('Button pressed!')">Button!</button>
  <a class="act-on" href="https://example.org" target="_blank">example.org</a>
</div>
yunzen
  • 32,854
  • 11
  • 73
  • 106
  • 1
    You could use a global variable as a flag that changes value when any of the event listeners are called. – AndrewL64 Jun 10 '21 at 11:57
  • @AndrewL64 But I want to know, if any event handler _including_ those that I have no control over have been called. – yunzen Jun 10 '21 at 11:59
  • what have you tried. Show some code to work on it. – Alireza Ahmadi Jun 10 '21 at 12:06
  • Have you considered [useCapture](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)? – James Jun 10 '21 at 12:18
  • @James How would you utilize `useCapture` here. I need to act in the bubbling phase. But only, if there is no other event that has handled this event before (deeper down in the DOM tree and thus earlier in the bubbling phase) – yunzen Jun 10 '21 at 12:35
  • You might want to take a look at [this](https://stackoverflow.com/a/16277194/1048572). There's [`.defaultPrevented`](https://developer.mozilla.org/en-US/docs/Web/API/Event/defaultPrevented) for checking if other handlers did handle the event, but it doesn't seem there's a way to detect whether an event *has* a default action. – Bergi Jun 10 '21 at 13:16
  • I'm not sure why you need to act in the bubbling phase. [Here](https://jsfiddle.net/ga4z6qx9/)'s an example that doesn't – James Jun 10 '21 at 14:00
  • I'll make this clear. Suppose have two links in my `card`. If I click anywhere on the card, I want the first link to be clicked. If I click on the second link, which is inside the card, I don't want the first link to be clicked. – yunzen Jun 11 '21 at 07:27
  • @yunzen [Nested links are illegal HTML](https://stackoverflow.com/q/18666915/1048572). [Don't do that](https://stackoverflow.com/q/9882916/1048572). If you insist, put an event listener on the second that stops propagation. – Bergi Jun 11 '21 at 09:34
  • @bergi I do not nest links. They are to completely separate from each other. They differ such that the first link (only as an example) would devise the action when clicking anywhere on the card and the other is not. What I don't want is that the first link should be clicked (with JS), when the second one is clicked. – yunzen Jun 11 '21 at 09:36
  • @bergi I replaced the inner link with a button – yunzen Jun 11 '21 at 09:54
  • @yunzen [That's not valid either](https://stackoverflow.com/q/6393827/1048572) :-P – Bergi Jun 11 '21 at 09:57
  • @bergi OK, I dropped the fourth card altogether. It seems to be a bit misleading about the aim of my question and it is not that important to the question as well – yunzen Jun 11 '21 at 09:59

0 Answers0