onclick not firing if element is reinserted into DOM mid-click
Asked Answered
S

2

10

I made a simple popup manager, which used the dom to decide which popup should be in front, without any z-index rule : when I click on a popup, it's moved in first position, so it is on top of the other popup. Unfortunately : this dom movement breaks the onclick event in my popup.

I made a simple case of the issue : the following code should output the three click events : mousedown, mouseup and click, it works on Firefox, and I think it used to work in previous versions of Chrome, but it doesn't anymore.

<div>
  <div onmousedown="console.log('mousedown');this.parentElement.appendChild(this);" onmouseup="console.log('mouseup');" onclick="console.log('click');">Click</div>
</div>

Do you know how can I fix this issue, and get back my onclick event ?

Sholley answered 13/11, 2017 at 16:13 Comment(0)
B
4

If reinserting an element into the DOM stops its click event from firing, then the other option would be to move its siblings.

This seems to work (I recommend viewing in full page mode because the console output will interrupt the events if it covers up a div you've just clicked):

function moveToFront(el) {
  var parent = el.parentElement;

  while (el.nextSibling) { 
    parent.insertBefore(el.nextSibling, el); 
  }
}

[].slice.call(document.getElementsByClassName('moveable')).forEach(function(el) {
  el.addEventListener('mousedown', function() {
    console.log('mousedown', this.id);
    moveToFront(this);
  });
  el.addEventListener('mouseup', function() {
    console.log('mouseup', this.id);
  });
  el.addEventListener('click', function() {
    console.log('click', this.id);
  });
});
.moveable {
  width: 100px;
  height: 100px;
  position: absolute;
}

#div1 {
  background-color: green;
  top: 10px;
  left: 10px;
}

#div2 {
  background-color: red;
  top: 40px;
  left: 40px;
}

#div3 {
  background-color: yellow;
  top: 20px;
  left: 70px;
}
<div>
  <div id="div1" class="moveable">Click</div>
  <div id="div2" class="moveable">Click</div>
  <div id="div3" class="moveable">Click</div>
</div>
Bocage answered 13/11, 2017 at 16:48 Comment(3)
Works on Chrome, works on IE11 (which the OP's didn't), and continues to work on Firefox. (The ones I have handy.) Nice! Weird, and would worry me in terms of fragility. But nice!Castigate
Looks easier than touching the events, works really good. +1 I would be careful with too many siblings/children - may hurt performance (Not a problem for OP I think)Piss
@RicardoRibeiro Yeah, I've just changed it so it only moves the siblings that are after the target element. Seems to still work.Bocage
A
0

It's not that event stops firing, it's just that you are not clicking the divs with the event anymore.

Be careful on zIndexing since zIndex is relative to it's container. You cannot have a container with less zIndex than it's parent or you will move it behind it. The "dirty" solution is to have zIndex grow with every click:

<style type="text/css">
html, body{
    width: 100%;
    height: 100%;
}

.Movable{
    height: 100px;
    position: absolute;
    width: 100px;
}

.black{
    background-color: black;
}

.gray{
    background-color: gray;
}

.wheat{
    background-color: lightgray;
}

<div style="position: relative; z-index: 20;">
    <p id="log" style="height: 1em; overflow-y: scroll;"></p>
    <div onclick="log( 'clicked', this )" onmousedown="log( 'mousedown', this )" onmouseup="log( 'mouseup', this )" class="Movable black"></div>
    <div onclick="log( 'clicked', this )" onmousedown="log( 'mousedown', this )" onmouseup="log( 'mouseup', this )" style="left: 25px; top: 55px;" class="Movable gray"></div>
    <div onclick="log( 'clicked', this )" onmousedown="log( 'mousedown', this )" onmouseup="log( 'mouseup', this )" style="left: 55px; top: 75px;" class="Movable wheat"></div>
</div>
<script type="text/javascript">
    var index = 1;
    function log( msg, element )
    {
        element.style.zIndex = index++;
        document.getElementById( 'log' ).innerHTML += "Log: " + msg + " -> " + element.className + "</br>";
    }
</script>
Aargau answered 13/11, 2017 at 17:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.