Search code examples
javascripthtmleventslistenerstoppropagation

How to listen children's events when children stop propagation


I need to watch children's events in Document level, but if the children stop propagation by using method stopPropagation(), I cannot listen those events occur in children.

Can someone know a better way to do this?


EDIT: now I want to create an chrome extension to monitor DOM node event, but the event could be stopped propagation, and it is not a good practice to add extra listener to all nodes. Following example will show my question.

customer HTML fragment

<body>
  <input type="button" value="Click Me" id="b">
</body>

customer javascript

var button = document.querySelector('#b');
button.addEventListener('click', function(e) {
  console.log('Button has been clicked');
  e.stopPropagation();
});

chrome extension content scripts

document.addEventListener('click', function(e) {
  console.log('Node(' + e.target.nodeName + ') has been clicked');
  // this listener will not be invoked because event has been stopped
  // propagation.
});

Solution

  • You can use "capturing" to track an event before bubbling. There's a very good description of how capturing works (as contrasted with bubbling) in this article: Bubbling and capturing.

    In summary, all browsers except IE before IE9, send events down the chain to the leaf where the event occurred and then they bubble the events back up. Normal event listening only listens for the event on the actual object or for propagated events, but if you set the third argument to .addEventListener() to true, then it will also listen to events going down the chain where the document object will see the event FIRST before bubbling has even started or been cancelled.

    Here's a working snippet demo:

    // show output
    function log(x) {
        var div = document.createElement("div");
        div.innerHTML = x;
        document.body.appendChild(div);
    }
    
    // stop propagation on leaf click
    var leaf = document.getElementById("leaf");
    
    leaf.addEventListener("click", function(e) {
      log("leaf message - click in leaf, propagation stopped")
      e.stopPropagation();
    }, false);
    
    // capture listen
    document.addEventListener("click", function(e) {
      if (e.target === leaf) {
      	log("document message - click in leaf");
      }
    }, true);
    <div id="topParent">
      <div id="midParent">
        <div id="leaf">
        Click Here
        </div>
      </div>
    </div>