Search code examples
javascriptfunctioneventsnested

Is it possible to nest multiple events in javascript?


As a newcomer to JavaScript, I find this function intriguing, though I'm not entirely sure why it's designed the way it is. At times, it seems to achieve its intended purpose of keeping the div visible and in the same position when clicking another div, until clicking back on the original one. However, I'm puzzled by the intermittent behavior where the messages "The second click has been made =" and "The first click has been made = " are printed seemingly as if the if conditional is not being respected, even when only one click is made. Despite this confusion, I appreciate that the function appears well-designed and capable of fulfilling its objective under certain conditions.

let clickFuera = true;

function inOutHover(idDivCard, isHover, idPoligono) {
  const divCard = document.getElementById(idDivCard);
  const poligono = document.getElementById(idPoligono);

  const manejadorEventoMovMouse = function(e) {
    divCard.style.left = e.pageX + 40 + "px";
    divCard.style.top = e.pageY + 5 + "px";
  };

  const manejadorEventoClick = function() {
    if (clickFuera) {
      document.removeEventListener("mousemove", manejadorEventoMovMouse);
      divCard.manejadorEventoMovMouse = null;
      divCard.style.display = "block";
      clickFuera = false;
      console.log("The first click has been made  = " + clickFuera);
    } else {
      poligono.removeEventListener("click", manejadorEventoClick);
      divCard.style.display = "none";
      clickFuera = true;
      console.log("The second click has been made = " + clickFuera);
    }
  };

  if (isHover) {
    divCard.manejadorEventoMovMouse = manejadorEventoMovMouse;
    document.addEventListener("mousemove", divCard.manejadorEventoMovMouse);
    poligono.addEventListener("click", manejadorEventoClick);
    divCard.style.display = "block";
  } else {
    if (divCard.manejadorEventoMovMouse) {
      document.removeEventListener("mousemove", divCard.manejadorEventoMovMouse);
      divCard.manejadorEventoMovMouse = null;
    }
    divCard.style.display = "none";
    poligono.removeEventListener("click", manejadorEventoClick);
  }
}
body {
  font-family: Arial, sans-serif;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f0f0f0;
  margin: 0;
}

.poligono {
  width: 100px;
  height: 100px;
  background-color: #3498db;
  cursor: pointer;
}

.divCard {
  display: none;
  position: absolute;
  background-color: #fff;
  border: 1px solid #ccc;
  padding: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
<body>
  <div id="poligono" class="poligono" onmouseover="inOutHover('divCard', true, 'poligono')" onmouseout="inOutHover('divCard', false, 'poligono')"></div>
  <div id="divCard" class="divCard">This is a card</div>

  <script src="script.js"></script>
</body>

I've attempted to review the code and ensure that the events are properly executed, but I'm still perplexed by the inconsistent behavior. Sometimes it seems to work as expected, while other times it doesn't. It's been a challenge to pinpoint the exact reason behind this variability. Despite my efforts to understand and debug the code, I'm left wondering why it functions correctly on some occasions but fails to do so on others.


Solution

  • You create new functions for the event handlers every time you execute inOutHover thus you don't remove event listeners since you pass a different (new) event listener to remove.

    So you should have only 1 instance of each event handler, you can do that this way:

    let clickFuera = true, manejadorEventoClick, manejadorEventoMovMouse;
    
    function inOutHover(idDivCard, isHover, idPoligono) {
      const divCard = document.getElementById(idDivCard);
      const poligono = document.getElementById(idPoligono);
    
      manejadorEventoMovMouse ??= function(e) {
        divCard.style.left = e.pageX + 40 + "px";
        divCard.style.top = e.pageY + 5 + "px";
      };
    
      manejadorEventoClick ??= function() {
        if (clickFuera) {
          document.removeEventListener("mousemove", manejadorEventoMovMouse);
          divCard.manejadorEventoMovMouse = null;
          divCard.style.display = "block";
          clickFuera = false;
          console.log("The first click has been made  = " + clickFuera);
        } else {
          poligono.removeEventListener("click", manejadorEventoClick);
          divCard.style.display = "none";
          clickFuera = true;
          console.log("The second click has been made = " + clickFuera);
        }
      };
    
      if (isHover) {
        divCard.manejadorEventoMovMouse = manejadorEventoMovMouse;
        document.addEventListener("mousemove", divCard.manejadorEventoMovMouse);
        poligono.addEventListener("click", manejadorEventoClick);
        divCard.style.display = "block";
      } else {
        if (divCard.manejadorEventoMovMouse) {
          document.removeEventListener("mousemove", divCard.manejadorEventoMovMouse);
          divCard.manejadorEventoMovMouse = null;
        }
        divCard.style.display = "none";
        poligono.removeEventListener("click", manejadorEventoClick);
      }
    }
    body {
      font-family: Arial, sans-serif;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f0f0f0;
      margin: 0;
    }
    
    .poligono {
      width: 100px;
      height: 100px;
      background-color: #3498db;
      cursor: pointer;
    }
    
    .divCard {
      display: none;
      position: absolute;
      background-color: #fff;
      border: 1px solid #ccc;
      padding: 10px;
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    }
    <body>
      <div id="poligono" class="poligono" onmouseover="inOutHover('divCard', true, 'poligono')" onmouseout="inOutHover('divCard', false, 'poligono')"></div>
      <div id="divCard" class="divCard">This is a card</div>
    
      <script src="script.js"></script>
    </body>