Search code examples
javascriptdom-events

Why Javascript event handler is called twice?


When I add an event handler to element of a class as follows:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    var divs = document.getElementsByClassName("class1");
    var onclick = function() {
      alert("clicked");
    }
    for (var i = 0; i < divs.length; i++) {
      divs[i].addEventListener("click", onclick);
    }
  </script>
</body>

</html>

The alert window is popped up twice if I click on the div element. But if I use the following code, the alert window is only popped up once.

<html>

<head>
  <title>test</title>
</head>

<body>
  <div class="class1" id="div1">div1</div>
  <script>
    var divs = document.getElementsByClassName("class1");
    var onclick = function() {
      alert("clicked");
    }

    divs.addEventListener("click", onclick);
  </script>
</body>

</html>

The following code also pops up the alert window twice:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    var div = document.getElementById("div1");
    var onclick = function() {
      alert("clicked");
    }
    div.addEventListener("click", onclick);
  </script>
</body>

</html>

I wonder why the event handler is called twice, regardless I use addEventListener("click",onclick, true); or addEventListener("click",onclick,false);

I use Firefox browser.


Solution

  • This is happening because your onclick variable is a global variable, and that means you are essentially doing this when you assign the function to onclick:

    window.onclick = function () {
        alert('click');
    };
    

    So you are adding the event listener to your divs, and window, and when you click the div, it is firing once on the div, and once on the window.

    To avoid this, use an iife to shield your variables from the global scope:

    <html>
    
    <head>
      <title>test</title>
    </head>
    
    <body>
    
      <div class="class1" id="div1">div1</div>
    
      <script>
        (function () {
            var divs = document.getElementsByClassName("class1");
            var onclick = function() {
              alert("clicked");
            }
            for (var i = 0; i < divs.length; i++) {
              divs[i].addEventListener("click", onclick);
            }
        })();
      </script>
    </body>
    
    </html>