Search code examples
javascriptevent-bubbling

trigger click event on parent with bubbling


I want to manually fire a click event on a parent container with dispatchEvent. The event bubbling does not seem to work.

// trigger click event on parent container
parent.dispatchEvent(new MouseEvent("click", {
    bubbles: true,
    cancelable: true,
    view: window,
    clientX: 4,
    clientY: 4
}));

...

child.addEventListener('click', function(e) {
    alert('click')
}, false);

See this fiddle:

https://jsfiddle.net/o4j0cjyp/2/


Solution

  • Events bubble up or not at all. The only way I know to bubble down would be to get all the elements in the targeted element, and iterate over the collection dispatching an event on all of them, some of them, or whatever your situation needs. This could be bad as if you do not tell the event not to bubble you could easily end up in a infinite loop.

    A better way to go about your goal is to use event delegation, where you use a common parent as the event listener element. Then when the event happens check the event target, if it is one you want than do whatever work.

    So for your html

    <div id="parent-container">
      <div id="child-container">
        this area has a click listener
      </div>
    </div>
    <div id="click-info">No 'click' event yet.</div>
    <div class="btn" id="trigger-parent-btn">
      trigger 'click' event on parent container<br>
      [ does not work ]
    </div>
    <div class="btn" id="trigger-child-btn">
      trigger 'click' event directly on child container
    </div>
    

    Instead of setting up event listeners on each one, and trying to trigger a child or parent event, we can setup a click listener on a common parent (in this case <body>). In there we can test if the target element is one of the three we want to trigger showing click info, if so do show the info.

    var info = document.querySelector("#click-info");
    document.body.addEventListener("click",function(event){
      var target = event.target;
      if(target.classList.contains("btn") || target.id=="child-container"){
        info.innerHTML = 'Clicked at ' + event.clientX + ':' + event.clientY;
      }
    })
    <div id="parent-container">
      <div id="child-container">
        this area has a click listener
      </div>
    </div>
    <div id="click-info">No 'click' event yet.</div>
    <div class="btn" id="trigger-parent-btn">
      trigger 'click' event on parent container<br>
      [ does not work ]
    </div>
    <div class="btn" id="trigger-child-btn">
      trigger 'click' event directly on child container
    </div>